如何为SwiftUI .searchable修饰符添加⌘F搜索快捷键支持
编辑
iOS 17及以上版本已有原生支持的实现方案。
原帖内容
.searchable视图修饰符是iOS 15 SwiftUI 3.0推出的新特性之一,下方是其基础使用示例。我希望能像大多数应用一样,实现按下⌘F触发搜索的功能,请问该如何实现?据我所知.keyboardShortcut修饰符仅能用于Button视图,限制较大,是否有可行的实现方式或替代方案?谢谢!
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) } } }
实现方案
iOS 17+ 版本实现
iOS 17新增了搜索框焦点绑定能力,配合@FocusState和快捷键即可实现:
struct ContentView: View { @State var searchText = "" @FocusState var isSearchFocused: Bool 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 { // iOS16及以上推荐用NavigationStack替代NavigationView NavigationStack { List { ForEach(filteredFruits, id: \.self) { fruit in Text(fruit.capitalized) } } .navigationTitle("Search") .searchable(text: $searchText, isPresented: $isSearchFocused) .focused($isSearchFocused) // 添加隐藏的快捷键触发按钮 .background { Button("") { isSearchFocused = true } .keyboardShortcut("f", modifiers: .command) .opacity(0) } } } }
iOS 15 ~ iOS 16 兼容版本
低版本没有原生的搜索框焦点绑定接口,可以通过遍历响应者链的方式激活搜索框:
extension UIApplication { func activateSearchBar() { guard let window = connectedScenes .filter({ $0.activationState == .foregroundActive }) .compactMap({ $0 as? UIWindowScene }) .first?.windows .first(where: \.isKeyWindow) else { return } // 遍历视图树找到UISearchBar实例 func findSearchBar(in view: UIView) -> UISearchBar? { for subview in view.subviews { if let searchBar = subview as? UISearchBar { return searchBar } else if let found = findSearchBar(in: subview) { return found } } return nil } findSearchBar(in: window)?.becomeFirstResponder() } } // 主视图代码 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) .background { Button("") { UIApplication.shared.activateSearchBar() } .keyboardShortcut("f", modifiers: .command) .opacity(0) } } } }
内容的提问来源于stack exchange,提问作者Denny L.
相关产品推荐
相关产品推荐

