Denny L.
Denny L.

Reputation: 391

Key command for searchable modifier on macOS

Edit

There is a solution for iOS 17 onwards now


Original Post

One of the new features introduced in iOS 15 SwiftUI 3.0 was the .searchable view modifier. Here is a simple example of how it works below. I would like to add the ability to search by pressing ⌘F as most apps have. How can I implement that functionality? As far as I am aware the .keyboardShortcut modifier can only be used on Button views which is quite limiting. Is there a way or workaround? Thanks! :)

struct ContentView: View {
    @State var searchText = ""
    private let fruits = ["apple", "banana", "plum", "grape"]
    
    var filteredFruits: [String] {
        if !searchText.isEmpty {
             return fruits.filter { $0.starts(with: searchText.lowercased()) }
        } else {
            return fruits
        }
    }

    var body: some View {
        NavigationView {
            List {
                ForEach(filteredFruits, id: \.self) { fruit in
                    Text(fruit.capitalized)
                }
            }
            .navigationBarTitle("Search")
            .searchable(text: $searchText) // Need to add key command to search (⌘F)
        }
    }
}

Upvotes: 15

Views: 3135

Answers (2)

Denny L.
Denny L.

Reputation: 391

Here I am, 2 years later and we have a response from Apple.

As of iOS 17 you can now use .searchable(text: Binding<String>, isPresented: Binding<Bool>)

struct ContentView: View {
    @State private var searchText = ""
    @State private var isSearching = false
    private let fruits = ["apple", "banana", "plum", "grape"]
    
    var filteredFruits: [String] {
        if !searchText.isEmpty {
             return fruits.filter { $0.starts(with: searchText.lowercased()) }
        } else {
            return fruits
        }
    }

    var body: some View {
        NavigationView {
            List {
                ForEach(filteredFruits, id: \.self) { fruit in
                    Text(fruit.capitalized)
                }
            }
            .navigationBarTitle("Search")
            .searchable(text: $searchText, isPresented: $isSearching)
            .background(Button("", action: { isSearching = true }).keyboardShortcut("f").hidden()) // some means to trigger the key command
        }
    }
}

Hope this helps you all :)

Upvotes: 9

George
George

Reputation: 30391

You can use SwiftUI-Introspect to get the underlying UISearchBar, and then create a hidden button triggered by the keyboard shortcut to focus the search bar.

The example below allows you to do F to activate the search bar.

Example:

struct ContentView: View {
    @State private var searchText = ""
    @State private var searchBar: UISearchBar?
    private let fruits = ["apple", "banana", "plum", "grape"]

    var filteredFruits: [String] {
        if !searchText.isEmpty {
             return fruits.filter { $0.starts(with: searchText.lowercased()) }
        } else {
            return fruits
        }
    }

    var body: some View {
        NavigationView {
            List {
                ForEach(filteredFruits, id: \.self) { fruit in
                    Text(fruit.capitalized)
                }
            }
            .navigationBarTitle("Search")
            .searchable(text: $searchText)
            .background(
                Button("Search fruits") {
                    focusSearchBar()
                }
                .keyboardShortcut("F", modifiers: .command)
                .hidden()
            )
        }
        .introspectNavigationController { nav in
            searchBar = nav.navigationBar.subviews.first { view in
                view is UISearchBar
            } as? UISearchBar
        }
    }

    private func focusSearchBar() {
        searchBar?.becomeFirstResponder()
    }
}

Result:

Result

Upvotes: 6

Related Questions