Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Contextual menu with search result for a NSSearchField

I would like to have a contextual menu that shows search results as text is entered in a search field. This is an image of the default mail app in OS X that does this. I know how to filter an array of strings according to the search request of the user, but I do not know how to display it this way. I am using Swift and for a Cocoa application. Any help is appreciated.

like image 535
S. Young Avatar asked Feb 07 '23 15:02

S. Young


2 Answers

Building from the previous answer, here is a simple Swift 3 class which you can use to automatically handle recent searches. You can add it as a custom class in your storyboard, or directly. It will look like this:

enter image description here

import Cocoa

class RecentMenuSearchField: NSSearchField {

    lazy var searchesMenu: NSMenu = {

        let menu = NSMenu(title: "Recents")

        let recentTitleItem = menu.addItem(withTitle: "Recent Searches", action: nil, keyEquivalent: "")
        recentTitleItem.tag = Int(NSSearchFieldRecentsTitleMenuItemTag)

        let placeholder = menu.addItem(withTitle: "Item", action: nil, keyEquivalent: "")
        placeholder.tag = Int(NSSearchFieldRecentsMenuItemTag)

        menu.addItem( NSMenuItem.separator() )

        let clearItem = menu.addItem(withTitle: "Clear Menu", action: nil, keyEquivalent: "")
        clearItem.tag = Int(NSSearchFieldClearRecentsMenuItemTag)

        let emptyItem = menu.addItem(withTitle: "No Recent Searches", action: nil, keyEquivalent: "")
        emptyItem.tag = Int(NSSearchFieldNoRecentsMenuItemTag)

        return menu
    }()

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

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

    //create menu
    private func initialize() {
        self.searchMenuTemplate = searchesMenu
    }
}
like image 151
Ryan Francesconi Avatar answered Feb 12 '23 22:02

Ryan Francesconi


NSSearchField searchMenuTemplate (NSMenu) contains Menu Items (NSMenuItem) with specific tags used by the Search Field to populate the Menu.

The recentSearches Array here is just to pass additional String used in complement of Recents Search strings and is not required (I thought that it was to store recent search but no). NSSearchField also clear this Array when the user clears Recents Search.

You can also configure a Menu with category, more info here: Configuring a Search Menu — Apple Developer

Example:

@IBOutlet weak var search: NSSearchField!

/// Array of string containing additional recents search (custom search)
var recentSearches = [String]()

/// Search Field Recents Menu
lazy var searchesMenu: NSMenu = {

    let menu = NSMenu(title: "Recents")

    let i1 = menu.addItem(withTitle: "Recents Search", action: nil, keyEquivalent: "")
    i1.tag = Int(NSSearchFieldRecentsTitleMenuItemTag)

    let i2 = menu.addItem(withTitle: "Item", action: nil, keyEquivalent: "")
    i2.tag = Int(NSSearchFieldRecentsMenuItemTag)

    let i3 = menu.addItem(withTitle: "Clear", action: nil, keyEquivalent: "")
    i3.tag = Int(NSSearchFieldClearRecentsMenuItemTag)

    let i4 = menu.addItem(withTitle: "No Recent Search", action: nil, keyEquivalent: "")
    i4.tag = Int(NSSearchFieldNoRecentsMenuItemTag)

    return menu
}()

override func viewDidLoad() {
    super.viewDidLoad()
    recentSearches = ["Toto","Titi","Tata"]
    search.delegate = self
    search.recentSearches = recentSearches
    search.searchMenuTemplate = searchesMenu
}
like image 45
Atika Avatar answered Feb 12 '23 23:02

Atika