You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 09:32:50