SwiftUI中Toolbar Principal位置TextField编辑时失去焦点原因咨询
嘿,我来帮你搞定这个搜索框失去焦点的问题!
问题根源
你遇到的这个情况,本质是因为放在ToolbarItem(placement: .principal)位置的TextField,会随着视图的频繁重建被重新初始化。当你输入文字时,searchText状态改变会触发List的过滤逻辑,导致整个SelectRegionView的body重新渲染——这时候导航栏里的TextField相当于被“重新造了一遍”,自然就丢了焦点。
解决办法
这里给你几个实用的方案,按需选就行:
方案1:用原生Searchable修饰符(iOS15+推荐)
如果你的最低支持版本能升到iOS15,直接用SwiftUI原生的.searchable就好,它自动在导航栏加搜索框,完全不会有焦点问题:
if #available(iOS 15.0, *) { List { makeListElements() } .navigationBarTitle("", displayMode: .inline) .searchable(text: $searchText, prompt: "Search") } else if #available(iOS 14.0, *) { // 保留iOS14的适配,或者用下面的方案2 List { makeListElements() } .navigationBarTitle("", displayMode: .inline) .toolbar(content: { ToolbarItem(placement: .principal) { SearchTextField(text: $searchText) } }) } else { // iOS13及以下的原有实现 List { makeListElements() } .navigationBarTitle("", displayMode: .inline) .add(searchBar) }
方案2:把TextField封装成独立View,手动管理焦点
把搜索框抽成单独的View,让SwiftUI能识别它的身份,再用@FocusState手动锁定焦点:
// 自定义搜索TextField组件 struct SearchTextField: View { @Binding var text: String @FocusState private var isFocused: Bool var body: some View { TextField("Search", text: $text) .focused($isFocused) .onAppear { // 可选:刚出现时自动聚焦 isFocused = true } .onChange(of: text) { _ in // 文本变化时确保焦点不丢 if !isFocused { isFocused = true } } } }
然后在Toolbar里用这个自定义组件代替原来的TextField就行。
方案3:自己做导航栏(兼容iOS14+)
如果需要完全自定义布局,可以隐藏系统导航栏,自己写一个带搜索框的导航栏:
if #available(iOS 14.0, *) { VStack(spacing: 0) { // 自定义导航栏 HStack { TextField("Search", text: $searchText) .padding(8) .background(Color(.systemGray5)) .cornerRadius(8) .padding(.horizontal) } .frame(height: 44) .background(Color(.systemBackground)) // 列表部分 List { makeListElements() } } .navigationBarHidden(true) // 隐藏系统自带导航栏 } else { // iOS13及以下的原有实现 List { makeListElements() } .navigationBarTitle("", displayMode: .inline) .add(searchBar) }
这种方式完全掌控导航栏的生命周期,不会因为列表刷新导致搜索框重建。
小建议
优先试试方案1,原生支持的最省心;如果必须兼容iOS14,方案2或3都能解决问题。
内容的提问来源于stack exchange,提问作者atom-22
相关产品推荐
相关产品推荐

