这种情况,在 @Willeke 发布的副本中已经有一个答案,但是 1)这个答案是 Objective-C 中的,而不是 Swift,2)我可以提供一个更详细的答案(带图片!),3)我我正在厚颜无耻地追求赏金(获取规则#110)。因此,考虑到这一点,我将如何实现您想要做的事情:
不要使用NSTextView
;使用一个NSTextField
,或者更好的是,一个NSSearchField
. NSSearchField
非常棒,因为我们可以在 Interface Builder 中进行设置,几乎不需要任何代码即可创建过滤谓词。为此,我们所要做的就是创建一个NSPredicate
属性在我们的视图控制器中,然后设置搜索字段的绑定检查器以指向它:
然后,您可以创建一个数组控制器,其过滤谓词绑定到同一属性,并且其Content Array
绑定到视图控制器上的属性:
当然,将表视图绑定到数组控制器:
最后但并非最不重要的一点是将表格单元格视图中的文本字段绑定到title
财产:
通过 Interface Builder 中的所有设置,我们几乎不需要任何代码。我们所需要的只是定义Project
类(所有属性都需要标记@objc
以便 Cocoa Bindings 系统可以看到它们):
class Project: NSObject {
@objc let title: String
init(title: String) {
self.title = title
super.init()
}
}
我们还需要项目、数组控制器和过滤器谓词的视图控制器上的属性。过滤谓词需要是dynamic
这样 Cocoa Bindings 可以在更改并更新 UI 时收到通知。如果projects
可以改变,使之dynamic
如此一来,对它的任何更改都会反映在 UI 中(否则,您可以摆脱dynamic
就做到了@objc let
).
class ViewController: NSViewController {
@IBOutlet var arrayController: NSArrayController!
@objc dynamic var projects = [
Project(title: "Foo"),
Project(title: "Bar"),
Project(title: "Baz"),
Project(title: "Qux")
]
@objc dynamic var filterPredicate: NSPredicate? = nil
}
最后但并非最不重要的一点是,我们的视图控制器的扩展使其符合NSSearchFieldDelegate
(or NSTextFieldDelegate
如果你正在使用NSTextField
而不是NSSearchField
),我们将在其上实现control(:textView:doCommandBy:)
方法。基本上,我们拦截搜索字段的字段编辑器执行的文本编辑命令,如果我们得到moveUp:
or moveDown:
, 返回true
告诉字段编辑器我们将处理这些命令。对于除这两个选择器之外的所有内容,返回false
告诉字段编辑器执行通常执行的操作。
请注意,这就是您应该使用NSTextField
or NSSearchField
而不是一个NSTextView
;该委托方法只会被调用NSControl
子类,其中NSTextView
is not.
extension ViewController: NSSearchFieldDelegate {
func control(_: NSControl, textView _: NSTextView, doCommandBy selector: Selector) -> Bool {
switch selector {
case #selector(NSResponder.moveUp(_:)):
self.arrayController.selectPrevious(self)
return true
case #selector(NSResponder.moveDown(_:)):
self.arrayController.selectNext(self)
return true
default:
return false
}
}
}
Voilà!
(当然,如果您更喜欢手动填充表视图而不是使用绑定,则可以忽略其中大部分内容并只需实现control(:textView:doCommandBy:)
,手动更新表的选择,而不是要求阵列控制器执行此操作。当然,使用绑定会产生漂亮、干净的代码,这就是我更喜欢它的原因。)