SwiftUI中如何流畅实现编程式聚焦搜索TextField并解决键盘关闭后的异常问题
SwiftUI中如何流畅实现编程式聚焦搜索TextField并解决键盘关闭后的异常问题
我明白你遇到的困扰了——编程式激活搜索框时动画卡顿,下滑关闭键盘后再次点击激活按钮,还会出现搜索文本消失但筛选效果依然生效的异常。咱们来一步步修复这个问题:
问题根源分析
你之前通过keyboardDidHide通知强制将isSearchFieldPresented设为false,这是导致状态混乱的核心原因。当用户下滑关闭键盘时,搜索框本身其实还处于显示状态(只是键盘被收起),手动修改isSearchFieldPresented会打破SwiftUIsearchable组件内部的状态同步逻辑,进而引发后续激活时的文本丢失问题。
解决方案与优化代码
我们可以通过以下调整来实现流畅的编程式聚焦,并解决状态异常:
- 移除手动干预
isSearchFieldPresented的代码:删掉onReceive(keyboardDidHide)的监听逻辑,让searchable组件自行管理显示状态。 - 使用
@FocusState管理搜索框焦点:通过焦点状态控制,让编程式聚焦的动画更自然流畅。 - 同步激活状态与焦点:在点击激活按钮时,先确保搜索框处于显示状态,再延迟设置焦点,保证UI渲染完成后键盘能顺利弹出。
以下是修正后的完整代码:
import SwiftUI struct AnimalView: View { @State private var animals = [ Animal(name: "Cat"), Animal(name: "Dog"), Animal(name: "Elephant"), Animal(name: "Lion"), Animal(name: "Zebra") ] @State private var searchText = "" @State private var selectedAnimalID: UUID? @State private var isSearchFieldPresented: Bool = false // 添加FocusState变量管理搜索框焦点 @FocusState private var isSearchFieldFocused: Bool var filteredAnimals: [Animal] { searchText.isEmpty ? animals : animals.filter { $0.name.localizedCaseInsensitiveContains(searchText) } } var body: some View { VStack{ NavigationSplitView { List(filteredAnimals, selection: $selectedAnimalID) { animal in Text(animal.name) } .searchable( text: $searchText, isPresented: $isSearchFieldPresented ) .textInputAutocapitalization(.never) .autocorrectionDisabled(true) .scrollDismissesKeyboard(.interactively) // 将搜索框的焦点状态与我们的变量绑定 .focused($isSearchFieldFocused) } detail: { if let id = selectedAnimalID, let animal = animals.first(where: { $0.id == id }) { Text("Selected: \(animal.name)") } else { Text("Select an animal") } } Spacer() Text("Is Presented: \(isSearchFieldPresented)") Button("Activate Search", action: { // 先显示搜索框 isSearchFieldPresented = true // 延迟设置焦点,确保UI渲染完成 DispatchQueue.main.async { isSearchFieldFocused = true } }) } } } struct ContentView: View { var body: some View { AnimalView() } } class Animal: Identifiable { let id = UUID() let name: String init(name: String) { self.name = name } }
额外优化建议
如果你希望用户下滑关闭键盘时同时隐藏搜索框,可以在searchable中配置dismissButton为.always,让用户可以手动点击取消按钮关闭搜索框,这样状态同步会更自然:
.searchable( text: $searchText, isPresented: $isSearchFieldPresented, dismissButton: .always )
这样修改后,编程式激活搜索框的动画会变得流畅,而且状态同步问题也彻底解决了——下滑关闭键盘后,搜索框会保留输入的文本,再次点击激活按钮时,文本会正常显示,筛选状态也完全一致。
内容来源于stack exchange
相关产品推荐
相关产品推荐

