40

OSX 开发知识点汇总(五)

 5 years ago
source link: http://www.wxtlife.com/2018/08/27/osx-dev-summary-5/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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

TableView 的使用

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

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

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

tableView.delegate = self
tableView.target = self

下面为实现 NSTableViewDelegate 接口

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 回调中设置相应的值。

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

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()
    }
    
}
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 上设置,同时记得把类指定为我们定义的类型。

示例如下:

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

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK