1.添加表格
这里使用的是xib,在xib文件添加 Table View即可
xib文件里添加的表格通常在Scroll View(可滚动区域)里面,当有很多条数据时可以通过滚动鼠标展示更多数据
以下是Table View属性面板的一些基本属性
- Content Mode:内容模式,有View Based和Cell Based,通常用View Based,这个更灵活,Cell Based用的少,不熟
- View Based:每个表格行由一个单独的 NSCell 对象表示
- Cell Based:每个表格行由一个或多个自定义的 NSView 对象表示
- column:列
剩下的有机会慢慢看,鼠标移动到上面会有介绍功能
2.列
需要显示多少列除了在xib文件里设置外还可以通过纯代码的方式实现,同时可以设置列的Title。
下面是使用代码添加列的示例代码:
// 清空默认的列
tableView.tableColumns.forEach { column in
tableView.removeTableColumn(column)
}
// 创建表格的列,并设置标题
let column1 = NSTableColumn(identifier:NSUserInterfaceItemIdentifier(rawValue: "column1"))
let column2 = NSTableColumn(identifier:NSUserInterfaceItemIdentifier(rawValue: "column2"))
let column3 = NSTableColumn(identifier:NSUserInterfaceItemIdentifier(rawValue: "column3"))
column1.title = "第一列"
column2.title = "第二列"
column3.title = "第三列"
// 将列添加到表格中
tableView.addTableColumn(column1)
tableView.addTableColumn(column2)
tableView.addTableColumn(column3)
NSTableView的tableColumns属性里放的是列,在代码中我们先遍历这个数组,移除xib文件添加的列。
然后创建几个NSTableColumn对象,identifier是列的唯一标识符,后面会用到,title是列的表头名,如何表格设置了隐藏表头则不会显示。
使用addTableColumn方法可以把列添加到表格里,先添加的会显示在前面。效果如下:
3.显示数据
添加需要的列之后该如何展示数据呢?直接添加行可以吗?
NO! NO! NO!
官方的帮助文档里说,NSTableView并不存储数据,它需要一个数据源并从里面检索值,需要了解更多需要查看 NSTableViewDataSource.
NSTableViewDataSource是个协议,里面提供了一些方法用来向表格提供数据和编辑数据。
主要看 numberOfRows(in:) 方法
具体使用方法看下面:
1.准备需要展示的数据,推荐把数据放在数组里
// 添加一个属性,并初始化
let rowData = [["A1", "B1", "C1"],
["A2", "B2", "C2"],
["A3", "B3", "C3"]]
2.给数据所在的类添加 NSTableViewDataSource 协议
3.实现 NSTableViewDataSource 协议中的 numberOfRows(in:) 方法
func numberOfRows(in tableView: NSTableView) -> Int {
return rowData.count // 返回多少行
}
这个方法返回几就有几行数据
4.把 tableView 的 dataSource 属性设为数据所在的类
tableView.dataSource = self // 我这都在一个类,所以是self
运行起来后发现是白的,没有内容,但是调试可以看见已经有三行,只是没有内容
接下来就需要使用代理方法把我们需要的内容添加到每一行中
需要使用的是 NSTableViewDelegate 协议
NSTableViewDelegate 协议的 tableView(_:viewFor:row:) 方法可以通过行和列显示视图
下面讲讲如何用
1.添加协议,把 tableView 的 delegate 属性
tableView.delegate = self
2.实现 tableView(_:viewFor:row:) 方法
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
// 获取列的唯一标识符
let columnIdentifier = tableColumn?.identifier
if columnIdentifier == nil {
return nil
}
// 获取单元格对应的cellView
var cell = tableView.makeView(withIdentifier: columnIdentifier!, owner: nil) as? NSTableCellView
if cell == nil {
cell = NSTableCellView()
cell?.identifier = columnIdentifier
}
// 获取cellView的textField
var textView = cell?.textField
if textView == nil {
textView = NSTextField()
textView!.isEditable = false
textView!.isBezeled = false
textView?.drawsBackground = false
textView?.textColor = NSColor.black
// 将文本框添加到单元格视图中
cell?.addSubview(textView!)
cell?.textField = textView
// 设置文本框的约束,例如设置文本框与单元格视图的边距等
textView!.translatesAutoresizingMaskIntoConstraints = false
textView!.leadingAnchor.constraint(equalTo: cell!.leadingAnchor, constant: 10).isActive = true
textView!.trailingAnchor.constraint(equalTo: cell!.trailingAnchor, constant: -10).isActive = true
textView!.topAnchor.constraint(equalTo: cell!.topAnchor, constant: 5).isActive = true
textView!.bottomAnchor.constraint(equalTo: cell!.bottomAnchor, constant: -5).isActive = true
}
// 获取列的位置
let columnNumb = tableView.column(withIdentifier: columnIdentifier!)
textView?.stringValue = rowData[row][columnNumb]
return cell
}
最终显示的结果
除了在单元格了添加文字视图外还能添加按钮、图片等视图,需要注意的是,如果在xib文件里添加列,并使用xib文件的列,默认是有NSTextField视图的,因为前面我移除了,是使用代码添加的列,所以没有,手动创建的 NSTableCellView 对象里面是没有 NSTextField 的,即使使用了textField属性也没用。
4.修改表头样式
通常情况下默认的表头不能满足我们的需求,这时需要修改表头的样式,但是当查看表头(NSTableHeaderView)的帮助文档时会发现几乎不能修改表头的样式,这就尴尬😓。
为了能够使表头满足我们的需求,通常的处理方法是自定义表头,通过重绘来达到我们想要的效果,下面会举一个例子,使用自定义表头修改表头背景颜色、字体颜色、字体大小和表头高度。
1.创建一个自定义的表头类,继承 NSTableHeaderView
class MTableHeaderView: NSTableHeaderView {
// 声明一个背景颜色属性,用于修改背景颜色(默认白色)
var backgroundColor: NSColor = NSColor.white
var textColor: NSColor = NSColor.black // 文字颜色
var textFont: NSFont = NSFont.systemFont(ofSize: 12) // 文字字体
var leftmargin: Float = 0 // 文字左边距
var toptmargin: Float = 0 // 文字上边距
var height: Float = 0 { // 表头的高度
didSet(oldHeight) {
frame.size.height = CGFloat(height)
}
}
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
// 绘制背景颜色
backgroundColor.setFill()
dirtyRect.fill()
// 绘制表头文字
for i in 0...(tableView?.tableColumns.count ?? 0) - 1 {
let column = tableView?.tableColumns[i]
let headerCell = column?.headerCell
let title = headerCell?.title
var textRect = headerRect(ofColumn: i)
textRect.origin.x = textRect.origin.x + CGFloat(leftmargin)
textRect.origin.y = CGFloat(toptmargin)
let textAttributes: [NSAttributedString.Key: Any] = [
.font: textFont,
.foregroundColor: textColor
]
// 绘制文字
title!.draw(in: textRect, withAttributes: textAttributes)
}
}
}
先讲讲是如何绘制背景颜色的,这个简单,把一个颜色设置为我们需要的填充颜色,然后使用 fill 方法对区域进行填充,这样就得到了背景颜色,但是整块区域都会被填充,意味着原有的内容会被覆盖掉,这时需要重新绘制文字等内容。
再讲讲如何绘制文字,原理是通过获取表头列的Title,然后把Title绘制到对应的位置,在这里可以设置需要绘制文字的样式。
2.使用自定义表头
let tableHeader = MTableHeaderView()
tableHeader.backgroundColor = NSColor.red
tableHeader.textColor = NSColor.white
tableHeader.textFont = NSFont.systemFont(ofSize: 14)
tableHeader.leftmargin = 10
tableHeader.toptmargin = 18
tableHeader.height = 50
tableView.headerView = tableHeader
使用起来很简单,先实例化一个自定义表头对象,设置对应的属性,然后把 tableView 的 headerView 设置为自定义表头对象就可以了。
注:这些属性不是必要的,我这是为了方便修改才添加的属性。
看看效果
有点丑,主要是为了看见效果。
提示:发现没有,表头的分割线消失了,需要的话可以自己绘制上去,能把文字绘制上去了,再绘制一些分割线问题应该不大吧😁。
5.行
行(NSTableRowView)的修改会比较简单(也不一定),在不需要指定行的情况下可以修改行的高度、背景颜色、高亮颜色
1.修改背景颜色
func tableView(_ tableView: NSTableView, didAdd rowView: NSTableRowView, forRow row: Int) {
rowView.backgroundColor = NSColor.red.withAlphaComponent(0.3)
}
上面方法是 NSTableViewDelegate 的委托方法,在添加了行后会被调用,在这直接设置行的背景颜色。
2.修改行高
func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat {
return 28;
}
实现这个代理方法,返回一个 CGFloat 类型值就是行高。
3.修改选中高亮颜色
我们并不能直接修改选中的高亮颜色,就很烦,但是可以间接的修改。
先把选中的高亮样式设置为 none,就是样式效果。
tableView.selectionHighlightStyle = .none
然后在选中后的代理方法里把选中的行背景颜色设为我们想要的高亮颜色,其它未选择的行设置为普通的背景颜色。
func tableViewSelectionDidChange(_ notification: Notification) {
let count = tableView.numberOfRows
for i in 0..<count {
// 遍历行
let rowView = tableView.rowView(atRow: i, makeIfNecessary: false)
if i == tableView.selectedRow {
// 选中的行
rowView?.backgroundColor = NSColor.red.withAlphaComponent(0.8)
} else {
// 未选中的行
rowView?.backgroundColor = NSColor.red.withAlphaComponent(0.3)
}
}
}
这个是代理方法,在选择行后调用。
看看效果吧!!!
上点难度,现在需要当我鼠标悬浮时行的背景颜色要变为高亮,如何处理?
解决方法,通过自定义行,设置鼠标事件可以实现,这是其中一个方法(我就会这一个)
1.自定义行并重写鼠标事件
class MTableRowView: NSTableRowView {
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
// Drawing code here.
}
override func mouseEntered(with event: NSEvent) {
// 鼠标进入背景颜色
backgroundColor = NSColor.red.withAlphaComponent(0.5)
}
override func mouseExited(with event: NSEvent) {
// 鼠标移出背景颜色
backgroundColor = NSColor.red.withAlphaComponent(0.3)
}
}
2.使用自定义行
func tableView(_ tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? {
let mTableRow = MTableRowView()
return mTableRow
}
实现这个代理方法,然后返回自定义的行。
注:这个方法不能设置背景颜色,设置了没用
3.添加鼠标事件响应的区域
func tableView(_ tableView: NSTableView, didAdd rowView: NSTableRowView, forRow row: Int) {
rowView.backgroundColor = NSColor.red.withAlphaComponent(0.3)
// 添加事件相应区域
let trackingArea = NSTrackingArea(rect: rowView.bounds, options: [.mouseEnteredAndExited, .activeInKeyWindow], owner: rowView, userInfo: nil)
rowView.addTrackingArea(trackingArea)
}
在前面设置背景颜色的方法里添加就可以了,试过直接初始化的时候添加,没有!!
看看效果吧!!