宁波网站建设方式,商丘做网站的费用,企业联系电话,厦门 网站建设公司电话表格是非常重要和复杂的一个控件#xff0c;本节会用大量篇幅来把表格这东西力求讲清楚。
基本设置
表格结构
表格是 OS X 组件中为数不多采用了MVC设计模式来实现的控件#xff0c;即tableView–dataSource–Delegate#xff0c;这种分层架构给处理数据带来了极大的便利…表格是非常重要和复杂的一个控件本节会用大量篇幅来把表格这东西力求讲清楚。
基本设置
表格结构
表格是 OS X 组件中为数不多采用了MVC设计模式来实现的控件即tableView–dataSource–Delegate这种分层架构给处理数据带来了极大的便利性。先了解下表格的组成如下
NSTableView由NSTableHeaderView NSTableRowView组成NSScrollViewNSScrollView包装了NSTableView它和NSTableView构成了最外围的对象NSTableRowView 的视图由NSScrollView来管理NSTableHeaderView为表头由一组 NSTableHeaderCell 组成NSTableRowView表示内容区由一组 NSTableCellView组成 NSTableViewDataSource由多个NSTableColumn即列视图来定义NSTableRowView 的数据由NSTableViewDataSource来定义NSTableViewDataSource定义了一系列的显示回调方法NSTableViewDelegateNSTableRowView 的代理由NSTableViewDelegate来定义它提供了数据加载时的回调方法
以下是UI的层级结构
table 属性
content mode设置table的cell模式推荐使用view-basedcell-based是一种老设计columns表示表格有多少列header是否显示表头horizontal grid和 vertical grid是否显示表格线background color单元格背景色selection是否允许行多选
column 属性
title标题state是否可以编辑列名称identifer列的唯一标识符用于在数据源和代理回调中使用Table Cell View 的identifer用于数据量大时可从缓存中获取可复用的cell单元视图用于性能优化
设置表格外观
主要是颜色等外观样式 IBOutlet weak var tableView: NSTableView!func tableStyleConfig() {//表格网格线设置self.tableView.gridStyleMask [NSTableView.GridLineStyle.dashedHorizontalGridLineMask,NSTableView.GridLineStyle.solidVerticalGridLineMask]//表格背景self.tableView.backgroundColor NSColor.white//背景颜色交替self.tableView.usesAlternatingRowBackgroundColors true//表格行选中样式self.tableView.selectionHighlightStyle .regular}表格数据绑定
以下是三种表格数据绑定方法推荐第二种方式。
Cell-Based表格数据 首先修改 Table View 的Content Mode 为Cell Based 选择column修改identifier与程序代码中数据定义相匹配参考下边代码示例 可以往单元格中添加不同的 cell注意是cell而不是控件这样就可以实现表格中的个性化展示了如下图 设置TableView的Deletegate和DataSource为默认的View Controller拖动下图红框到UI导航的View Controller上面 也可以通过代码设置 self.tableView.delegate self和self.tableView.dataSource self 定义表格数据下面的updateData方法是自定义的需要调用 //表格数据这个datas属性会在协议实现时再加载使用var datas [NSDictionary]()func updateData() {self.datas [[name:john,address:USA,gender:male,married:(1)],[name:mary,address:China,gender:female,married:(0)],[name:park,address:Japan,gender:male,married:(0)],[name:Daba,address:Russia,gender:female,married:(1)],]}扩展协议加载数据
extension ViewController: NSTableViewDataSource {//返回表格数据行数func numberOfRows(in tableView: NSTableView) - Int {return self.datas.count}//正常只读显示func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) - Any? {let data self.datas[row]//表格列的标识let key tableColumn?.identifier//单元格数据let value data[key!]return value}
}View-Based表格数据推荐
首先修改 Table View 的Content Mode 为View Based选择column修改identifier与数据相匹配同上可以往单元格中添加不同的控件注意是控件而不是cell这样就可以实现表格中的个性化展示了设置TableView的Deletegate和DataSource为默认的View Controller同上定义表格数据同上扩展协议加载数据要实现两个协议
extension ViewController: NSTableViewDataSource {func numberOfRows(in tableView: NSTableView) - Int {return self.datas.count}
}extension ViewController: NSTableViewDelegate {func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) - NSView? {let data self.datas[row]//表格列的标识let key (tableColumn?.identifier)!//单元格数据let value data[key]//根据表格列的标识,创建单元视图let view tableView.makeView(withIdentifier: key, owner: self)let subviews view?.subviewsif (subviews?.count)!0 {return nil}if key.rawValue name || key.rawValue address {let textField subviews?[0] as! NSTextFieldif value ! nil {textField.stringValue value as! String}}if key.rawValue gender {let comboField subviews?[0] as! NSComboBoxif value ! nil {comboField.stringValue value as! String}}if key.rawValue married {let checkBoxField subviews?[0] as! NSButtoncheckBoxField.state NSControl.StateValue(rawValue: 0)if (value ! nil) {checkBoxField.state NSControl.StateValue(rawValue: 1)}}return view}}Bindings 表格数据
添加ArrayControl 控件然后绑定到View Controller的一个变量中 实现代码如下
import Cocoaclass ViewController: NSViewController {override func viewDidLoad() {super.viewDidLoad()updateData()}override var representedObject: Any? {didSet {// Update the view, if already loaded.}}dynamic var datas [NSDictionary]()func updateData() {self.datas [[name:john,address:USA],[name:mary,address:China],[name:park,address:Japan],[name:Daba,address:Russia],]}
}添加一个NSTableView控件设置tableColumn的identifier和上面的datas名称一样表格列绑定到Array ControllerModel Key Path可以省略单元格绑定到Model key path选顶中的objectValue表示当前的行数据
动态编辑表格 协议实现
表格的操作需要实现NSTableViewDataSource协议方法否则无法保存数据 //动态编辑表格使用func tableView(_ tableView: NSTableView, setObjectValue object: Any?, for tableColumn: NSTableColumn?, row: Int) {let data self.datas[row]//表格列的标识let key tableColumn?.identifierlet editData NSMutableDictionary.init(dictionary: data)editData[key!] objectself.datas[row] editData}添加和删除行 IBAction func addTableRow(_ sender: NSButton) {let data NSMutableDictionary()data[name] data[address] //增加数据到datas数据区self.datas.append(data)//刷新表数据self.tableView.reloadData()//定位光标到新添加的行self.tableView.editColumn(0, row: self.datas.count-1 , with: nil, select: true)}IBAction func deleteTableRow(_ sender: NSButton) {//表格当前选择的行let row self.tableView.selectedRow//如果row小于0表示没有选择行if row0 {return}//从数据区删除选择的行的数据self.datas.remove(at: row)//刷新表数据self.tableView.reloadData()}表格行拖放
注册一个自定义事件实现 NSTableViewDataSource 把表格行号数据拷贝到剪切板对象中实现 NSTableViewDataSource 把表格行号数据复制到表格对象中
//注册拖放事件事件为一自定义的值
let kTableViewDragDataTypeName TableViewDragDataTypeName
self.tableView.register(forDraggedTypes: [kTableViewDragDataTypeName])实现协议方法 func tableView(_ tableView: NSTableView, writeRowsWith rowIndexes: IndexSet, to pboard: NSPasteboard) - Bool {//将表格行号拷贝到剪切板对象中let zNSIndexSetData NSKeyedArchiver.archivedData(withRootObject: rowIndexes);pboard.declareTypes([kTableViewDragDataTypeName], owner: self)pboard.setData(zNSIndexSetData, forType: kTableViewDragDataTypeName)return true}func tableView(_ tableView: NSTableView, acceptDrop info: NSDraggingInfo, row: Int, dropOperation: NSTableViewDropOperation) - Bool {let pboard info.draggingPasteboard()let rowData pboard.data(forType: kTableViewDragDataTypeName)let rowIndexes NSKeyedUnarchiver.unarchiveObject(with: rowData!) as! NSIndexSetlet dragRow rowIndexes.firstIndexlet temp self.datas[row]self.datas[row] self.datas[dragRow]self.datas[dragRow] temptableView.reloadData()return true}表格事件
定义表格常见的一些操作事件
数据选取
以下是表格行和列的选取方法采用(X,Y)坐标系的方式 let row self.selectedRowlet col self.selectedColumn行单击事件
需要实现 NSTableViewDelegate 协议中的方法不需要设置绑定 func tableViewSelectionDidChange(_ notification: Notification){let tableView notification.object as! NSTableViewlet row tableView.selectedRowprint(selection row \(row))}行双击事件
动态添加事件。 //表格双击事件self.tableView.doubleAction #selector(ViewController.doubleAction(_:))IBAction func doubleAction(_ sender: AnyObject ) {let row self.tableView?.selectedRowprint(double selection row \(row!))}表格右键菜单
拖动一个NSMenu到设计面板绑定menu对象到ViewController中实现NSMenuDelegate协议
IBOutlet weak var tableMenu: NSMenu!
//表格菜单
self.tableView.menu self.tableMenu
self.tableView.menu?.delegate self实现协议
//表格上下文菜单协议
extension ViewController: NSMenuDelegate {func menuNeedsUpdate(_ menu: NSMenu) {menu.removeAllItems()NSLog(menu clicked !)}}不同菜单的写法
import Cocoaclass MyTableView: NSTableView {var menu1: NSMenu?var menu2: NSMenu?override func menu(for event: NSEvent) - NSMenu? {let row self.selectedRowlet col self.selectedColumnif (row 0 col 1) {return self.menu1}return self.menu2}
}表格排序 点击列头时出现排序升降箭头指示其算法也可以自定义在表格初始化后可调用一次以下几个方法之一 //表格排序func tableSortConfig() {for tableColumn in self.tableView.tableColumns {//升序排序let sortRules NSSortDescriptor(key: tableColumn.identifier.rawValue, ascending: true)tableColumn.sortDescriptorPrototype sortRules}}func tableSortConfig2() {for tableColumn in self.tableView.tableColumns {//升序排序 使用字符串标准的比较函数let sortRules NSSortDescriptor(key: tableColumn.identifier.rawValue, ascending: true, selector: #selector(NSString.localizedStandardCompare(_:)))tableColumn.sortDescriptorPrototype sortRules}}func tableSortConfig3() {for tableColumn in self.tableView.tableColumns {//升序排序let sortRules NSSortDescriptor(key: tableColumn.identifier.rawValue, ascending: true, comparator:{ s1,s2 inlet str1 s1 as! Stringlet str2 s2 as! Stringif str1 str2 {return .orderedAscending}if str1 str2 {return .orderedDescending}return .orderedSame})tableColumn.sortDescriptorPrototype sortRules}}编码实现
其实就是按步骤创建下列元素。 下面的代码需要完成以下界面效果
创建表格元素
基本元素定义 //1、定义表格对象和滚动条对象最外层对象let tableView NSTableView()let tableScrollView NSScrollView()//2、定义存储表格数据的变量var datas [NSDictionary]()其组装过程大概如下 //3、组装表格override func viewDidLoad() {super.viewDidLoad()//创建表格列self.tableViewConfig()//配置滚动条视图self.tableScrollViewConfig()//设置滚动条自动布局self.autoLayoutConfig()//加载更新数据self.updateData()}创建表头 func tableViewConfig() {self.tableView.focusRingType .none//self.tableView.autoresizesSubviews trueself.tableView.delegate selfself.tableView.dataSource selflet column1 NSTableColumn(identifier: NSUserInterfaceItemIdentifier(rawValue: name))column1.title namecolumn1.width 80column1.maxWidth 100column1.minWidth 50self.tableView.addTableColumn(column1)let column2 NSTableColumn(identifier: NSUserInterfaceItemIdentifier(rawValue: address))column2.title addresscolumn2.width 80column2.maxWidth 100column2.minWidth 50self.tableView.addTableColumn(column2)}设置滚动条样式
这块可有可无 func tableScrollViewConfig() {self.tableScrollView.hasVerticalScroller trueself.tableScrollView.hasVerticalScroller falseself.tableScrollView.focusRingType .noneself.tableScrollView.autohidesScrollers trueself.tableScrollView.borderType .bezelBorderself.tableScrollView.translatesAutoresizingMaskIntoConstraints falseself.tableScrollView.documentView self.tableViewself.view.addSubview(self.tableScrollView)}设置布局
此处建议使用了自动化布局窗口辅助此处使用的是Masony但如果用swiftui需要引入三方包 func autoLayoutConfig() {let topAnchor self.tableScrollView.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0)let bottomAnchor self.tableScrollView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0)let leftAnchor self.tableScrollView.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: 0)let rightAnchor self.tableScrollView.rightAnchor.constraint(equalTo: self.view.rightAnchor, constant: 0)NSLayoutConstraint.activate([topAnchor, bottomAnchor, leftAnchor, rightAnchor])}初始化数据
更新数据同时需要实现表格代理协议 func updateData() {self.datas [[name:john,address:USA],[name:mary,address:China],[name:park,address:Japan],[name:Daba,address:Russia],]self.tableView.reloadData()}实现NSTableViewDelegate协议
这里有很多方法可以按需定义
extension ViewController: NSTableViewDelegate {func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) - NSView? {let data self.datas[row]//表格列的标识let key (tableColumn?.identifier)!//单元格数据let value data[key]//根据表格列的标识,创建单元视图var view tableView.makeView(withIdentifier: key, owner: self)if view nil {let cellView NSTableCellView()cellView.identifier identifier;view cellViewlet textField NSTextField()textField.translatesAutoresizingMaskIntoConstraints falsetextField.isBezeled falsetextField.drawsBackground falsecellView.addSubview(textField)let topAnchor textField.topAnchor.constraint(equalTo: cellView.topAnchor, constant: 0)let bottomAnchor textField.bottomAnchor.constraint(equalTo: cellView.bottomAnchor, constant: 0)let leftAnchor textField.leftAnchor.constraint(equalTo: cellView.leftAnchor, constant: 0)let rightAnchor textField.rightAnchor.constraint(equalTo: cellView.rightAnchor, constant: 0)NSLayoutConstraint.activate([topAnchor,bottomAnchor,leftAnchor, rightAnchor])}let subviews view?.subviewsif (subviews?.count)!0 {return nil}let textField subviews?[0] as! NSTextFieldif value ! nil {textField.stringValue value as! String}return view}func tableView(_ tableView: NSTableView, heightOfRow row: Int) - CGFloat {return 30}}