更改搜索字段的图标

Change search field's icon

我尝试像 Xcode 那样实现搜索行为:如果您在搜索字段中输入内容,图标会改变颜色。

我将 searchFieldDidStartSearchingsearchFieldDidEndSearching 委托给控制器并更改图像。 问题是图标的图像只有在 window 失去焦点时才会改变。

class ViewController: NSViewController {
    @IBOutlet weak var searchField: NSSearchField!

    func searchFieldDidStartSearching(_ sender: NSSearchField) {
        print("\(#function)")

        (searchField.cell as! NSSearchFieldCell).searchButtonCell?.image = NSImage.init(named: "NSActionTemplate")
    }

    func searchFieldDidEndSearching(_ sender: NSSearchField) {
        print("\(#function)")

        (searchField.cell as! NSSearchFieldCell).searchButtonCell?.image = NSImage.init(named: "NSHomeTemplate")
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
    }

    override var representedObject: Any? {
        didSet {
        // Update the view, if already loaded.
        }
    }
}

提前感谢任何ideas/suggestions。

如您所见,当您在视图内部单击时,它仍然集中在搜索文本字段上(因为您在其下方单击后仍然可以在其中键入内容)。由于更改图像在失去焦点时处于打开状态,因此您应该检查是否在文本字段之外单击。

通过 subclassing NSSearchFieldCell 解决问题并将此 class 分配给字段的单元格。

虽然不知道是什么原因,但是有效:

NSApp.mainWindow?.resignMain()
NSApp.mainWindow?.becomeMain()

完整代码如下:

class MyViewController: NSViewController {
    private lazy var searchField: NSSearchField = {
        let searchField = NSSearchField(string: "")

        if let searchButtonCell = searchField.searchButtonCell {
            searchButtonCell.setButtonType(.toggle)
            let filterImage = #imageLiteral(resourceName: "filter")
            searchButtonCell.image = filterImage.tinted(with: .systemGray)
            searchButtonCell.alternateImage = filterImage.tinted(with: .systemBlue)
        }
        searchField.focusRingType = .none
        searchField.bezelStyle = .roundedBezel
        searchField.delegate = self

        return searchField
    }()

    ...
}

extension MyViewController: NSSearchFieldDelegate {
    func searchFieldDidStartSearching(_ sender: NSSearchField) {
        sender.searchable = true
    }

    func searchFieldDidEndSearching(_ sender: NSSearchField) {
        sender.searchable = false
    }
}

extension NSSearchField {
    var searchButtonCell: NSButtonCell? {
        (self.cell as? NSSearchFieldCell)?.searchButtonCell
    }

    var searchable: Bool {
        get {
            self.searchButtonCell?.state == .on
        }

        set {
            self.searchButtonCell?.state = newValue ? .on : .off
            self.refreshSearchIcon()
        }
    }

    private func refreshSearchIcon() {
        NSApp.mainWindow?.resignMain()
        NSApp.mainWindow?.becomeMain()
    }
}

extension NSImage {
    func tinted(with color: NSColor) -> NSImage? {
        guard let image = self.copy() as? NSImage else { return nil }
        image.lockFocus()
        color.set()
        NSRect(origin: NSZeroPoint, size: self.size).fill(using: .sourceAtop)
        image.unlockFocus()
        image.isTemplate = false
        return image
    }
}

我遇到了同样的问题。一个简单的覆盖为我解决了这个问题

extension NSSearchField{
    open override func draw(_ dirtyRect: NSRect) {
        super.draw(dirtyRect)
    }
}