iOS SwiftUI searchable修饰符提交后建议令牌未消失问题
带令牌的
searchable提交搜索后建议令牌列表不消失的问题 问题现象
使用带令牌的searchable视图修饰符时,预期行为是:
- 激活搜索字段时,建议令牌列表显示在结果列表上方
- 选择令牌并提交搜索(按回车)后,建议列表消失,结果视图重新显示
但实际出现的问题是:提交搜索后,建议令牌仍遮挡结果视图,仅能通过取消搜索关闭令牌列表(此操作会丢弃当前搜索查询)。
测试环境:iPad(iOS 16.4)模拟器及真机,真机曾间歇性正常,目前提交搜索后令牌视图均不消失,软硬键盘均已测试。
可复现代码
struct SearchableTest: View { @StateObject private var filterModel = TestFilterModel() var body: some View { NavigationSplitView { List { Text("Testrow 1") Text("Testrow 2") } .searchable(text: $filterModel.searchFilter, tokens: $filterModel.selectedTokens, suggestedTokens: $filterModel.suggestedTokens, placement: .navigationBarDrawer, prompt: "Search", token: { $0.tokenLabel }) } detail: { Text("Detail View") } .task { filterModel.load() } } } @MainActor final class TestFilterModel: ObservableObject { @Published var searchFilter = "" @Published var selectedTokens = [TestFilterToken]() @Published var suggestedTokens = [TestFilterToken]() func load() { self.suggestedTokens = [ .itemType("Type 1"), .itemType("Type 2"), .itemType("Type 3"), .status("Status 1"), .status("Status 2"), .status("Status 3"), ] } } // ======================================================= // // MARK: - Tokens // ======================================================= // enum TestFilterToken: Identifiable { case itemType(String) case status(String) var id: String { self.title } var tokenLabel: Label<Text, Image> { Label(title, systemImage: systemImage) } var title: String { switch self { case let .itemType(string), let .status(string): return string } } var systemImage: String { switch self { case .itemType: return "circle.fill" case .status: return "square.fill" } } }
问题分析
推测问题源于iOS 16.4中,键盘回车键的搜索提交行为未正确触发搜索字段失焦,导致建议令牌列表仍保持显示状态。此前正常时回车键显示“search”,按下可关闭建议视图,当前版本该行为出现异常。
解决方案
通过@FocusState控制搜索字段的焦点状态,在搜索提交时手动让搜索字段失去焦点,从而关闭建议令牌列表:
修改后的完整代码
struct SearchableTest: View { @StateObject private var filterModel = TestFilterModel() // 添加焦点状态变量 @FocusState private var isSearchFocused: Bool var body: some View { NavigationSplitView { List { Text("Testrow 1") Text("Testrow 2") } .searchable(text: $filterModel.searchFilter, tokens: $filterModel.selectedTokens, suggestedTokens: $filterModel.suggestedTokens, placement: .navigationBarDrawer, prompt: "Search", token: { $0.tokenLabel }) // 绑定焦点状态 .focused($isSearchFocused) // 监听搜索提交事件,手动失焦 .onSubmit(of: .search) { isSearchFocused = false } } detail: { Text("Detail View") } .task { filterModel.load() } } } @MainActor final class TestFilterModel: ObservableObject { @Published var searchFilter = "" @Published var selectedTokens = [TestFilterToken]() @Published var suggestedTokens = [TestFilterToken]() func load() { self.suggestedTokens = [ .itemType("Type 1"), .itemType("Type 2"), .itemType("Type 3"), .status("Status 1"), .status("Status 2"), .status("Status 3"), ] } } // ======================================================= // // MARK: - Tokens // ======================================================= // enum TestFilterToken: Identifiable { case itemType(String) case status(String) var id: String { self.title } var tokenLabel: Label<Text, Image> { Label(title, systemImage: systemImage) } var title: String { switch self { case let .itemType(string), let .status(string): return string } } var systemImage: String { switch self { case .itemType: return "circle.fill" case .status: return "square.fill" } } }
说明
- 添加
@FocusState private var isSearchFocused: Bool来跟踪搜索字段的焦点状态 - 通过
.focused($isSearchFocused)将焦点状态绑定到搜索字段 - 使用
.onSubmit(of: .search)监听搜索提交动作,触发时将isSearchFocused设为false,让搜索字段失焦,从而自动隐藏建议令牌列表
内容的提问来源于stack exchange,提问作者Cheezzhead
相关产品推荐
相关产品推荐

