OSX 开发知识点汇总(五)

想第一时间获取我的最新文章,请关注公众号: 技术特工队

TableView

在 OSX 中有一些列表的需求,这时候需要使用 OSX 中 TableView 来实现,但是这个 TableView 与 Android的 ListView 不太一样。使用还是比较复杂的。下面做一个简单的介绍,

TableView 的使用

  1. 首先需要在布局文件中,拖出一个TableView,并且添加相应的每列的数据源,主要是 使用 TableCellView, 里面默认的控件有一个TextFiled和一个ImageView,如果需要其他控件则需要自己进行自定义进行实现,下一小节会说到。

  2. 需要对 TableView 设置一个数据源,需要实现 NSTableViewDataSource接口, 并对 TableView 设置数据源,如下:

    1
    2
    3
    4
    5
    6
    7
    tableView.dataSource = self

    extension MainView: NSTableViewDataSource {
    func numberOfRows(in tableView: NSTableView) -> Int {
    return dataSources.count
    }
    }
  3. 对每行的数据进行渲染处理,设置delegatetarget代理,并实现 NSTableViewDelegate接口中如下方法

1
2
tableView.delegate = self
tableView.target = self

下面为实现NSTableViewDelegate接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
extension MainView: NSTableViewDelegate {
fileprivate enum CellIdentifiers {
static let avatarImgCell = NSUserInterfaceItemIdentifier("image")
static let nickNameCell = NSUserInterfaceItemIdentifier("name")
}

func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
let item = dataSouece[row]
// 图片的资源
var image: NSImage?
//名称
var nickName: String = ""
var cellIdentifier: NSUserInterfaceItemIdentifier = CellIdentifiers.nickNameCell
if tableColumn == tableView.tableColumns[0] {
image = #imageLiteral(resourceName: "member_avatar")
cellIdentifier = CellIdentifiers.avatarImgCell
} else if tableColumn == tableView.tableColumns[1] {
nickName = item.nickName
cellIdentifier = CellIdentifiers.nickNameCell
}
// 通过 NSUserInterfaceItemIdentifier 构建每一个 CellView
let view = tableView.makeView(withIdentifier: cellIdentifier, owner: nil)
if let cellItem = view as? NSTableCellView {
// 对 CellView 中默认控件进行设置每个资源
cellItem.textField?.stringValue = nickName
cellItem.imageView?.image = image
return cellItem
}
return nil
}
}

上面的方法可以对基本的 TableView 进行渲染处理,可以看到 NSTableCellView 类中也只有默认 textFiledNSImageView 控件,如果需要在一个NSTableCellView中有两个控件,或者有其他的控件如:NSButton等,则目前是无法完成的,那接下来就介绍下 NSTableCellView的自定义操作。

TableView 中 TableCellView的自定义

  1. 自定义NSTableCellView,首先先创建一个CustomerTableViewCell类,其继承自NSTableCellView,
  2. 其次主要在 xib 或者 storyboard 的 TableViewNSTableCellView 添加新的控件,或者移除掉原来的,添加新的控件进去,并设置相应的约束,与普通 View 操作一致的。最后将自定义的NSTableCellView的类名指定为自定义的类名。
  3. 将新添加的控件拖到CustomerTableViewCell中连线,这样 CustomerTableViewCell就可以控制自定义添加的控件了。
  4. 在上面的TableView 回调中设置相应的值。

我们拿上面的例子来改造下,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class CustomerNSTableCellView: NSTableCellView {

// 添加了一个 age 的label 在同一个CellView中
@IBOutlet weak var ageLabel: NSTextField!

override init(frame frameRect: NSRect) {
super.init(frame: frameRect)
}

required init?(coder: NSCoder) {
super.init(coder: coder)
}

override func awakeFromNib() {
super.awakeFromNib()
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
extension MainView: NSTableViewDelegate {
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
let item = dataSouece[row]
// 图片的资源
var image: NSImage?
//名称
var nickName: String = ""
var age : Int = 1
var cellIdentifier: NSUserInterfaceItemIdentifier = CellIdentifiers.nickNameCell
if tableColumn == tableView.tableColumns[0] {
image = #imageLiteral(resourceName: "member_avatar")
cellIdentifier = CellIdentifiers.avatarImgCell
} else if tableColumn == tableView.tableColumns[1] {
nickName = item.nickName
age = item.age
cellIdentifier = CellIdentifiers.nickNameCell
}
// 通过 NSUserInterfaceItemIdentifier 构建每一个 CellView
let view = tableView.makeView(withIdentifier: cellIdentifier, owner: nil)
if let cellItem = view as? NSTableCellView {
if cellItem is CustomerNSTableCellView {
let userCellItem = cellItem as! CustomerNSTableCellView
userCellItem.ageLabel.stringValue = age
userCellItem.textField?.stringValue = nickName
} else {
// 对 CellView 中默认控件进行设置每个资源
cellItem.textField?.stringValue = nickName // 这里默认的Cell里没有则控件会为空。
cellItem.imageView?.image = image
}
return cellItem
}
return nil
}
}

至此可以在每个 NSTableCellView中进行任意的自定义了,实现自己想要实现的功能。

NSStoryboardSegue 的自定义

NSStoryboardSegue 的功能是什么呢?官方文档是这样介绍的: A transition or containment relationship between two scenes in a storyboard. 也就是在多个 storyboard 或者 window 中进行的连线,这个连线可以定义一些功能,比如说show操作等等,比如我们点击一个按钮,打开(show)另外一个 window 则可以使用它进行连线操作后,这条线就是NSStoryboardSegue类型的。

那么为什么要自定义它呢? 因为如果在 storyboard 中对某个控件连线使用 NSStoryboardSegue 后,如果在对该控件执行 action 操作时,action操作会不起作用,这点需要吐槽下苹果的设计了。如果要想再使用NSStoryboardSegue后还可以指定其他操作,则只能自定义 NSStoryboardSegue了。

在自定义中复写perform()方法,可以添加自定义的一些操作了。
如果一个项目中有多个需要自定义,可以使用NSStoryboardSegue中的identifier来区分不同的NSStoryboardSegueidentifier 是在每个每条连线Segue上设置,同时记得把类指定为我们定义的类型。

示例如下:

1
2
3
4
5
6
7
class CustomerStoryboardSegue: NSStoryboardSegue {

override func perform() {
super.perform()
// 下面则可以做其他的事情了。通过self.identifier 来区分不同的 Sugue,
}
}

WangXin wechat
欢迎订阅我的微信公众号,第一时间获取最新文章!
坚持原创技术分享,您的支持将鼓励我继续创作!