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

SwiftUI中@FocusState在ScrollView内失效的原因及解决方法

ScrollView中@FocusState失效无法收起键盘的问题

正常工作的代码

当TextField直接放在VStack中时,@FocusState可以正常控制焦点,点击按钮能收起键盘:

struct ContentView: View {
    @State private var textInput = ""
    @FocusState private var isFocused: Bool
    
    var body: some View {
        VStack {
            TextField("Enter text", text: $textInput)
                .focused($isFocused)
            
            Button("Submit") {
                isFocused = false
            }
        }
    }
}

失效的场景

将TextField放入ScrollView后,点击按钮虽然会打印"Dismiss",但键盘无法收起,@FocusState失效:

struct ContentView: View {
    @State private var textInput = ""
    @FocusState private var isFocused: Bool

    var body: some View {
        ScrollView(.vertical) {
            TextField("Enter text", text: $textInput)
                .focused($isFocused)
            Button("Dismiss") {
                isFocused = false
                print("Dismiss")
            }
        }
    }
}

原因

ScrollView作为滚动容器,会自行管理内部控件的焦点响应链,它的内部环境会干扰@FocusState与TextField的绑定同步。直接更新@FocusState变量时,ScrollView的焦点管理逻辑会覆盖这个操作,导致TextField的焦点状态没有被正确修改,键盘也就无法收起。

解决方法

这里提供两种可靠的解决方式:

方法一:使用UIKit API强制收起键盘

直接调用UIKit的方法让所有响应器 resign 第一响应者,绕过ScrollView的焦点管理:

struct ContentView: View {
    @State private var textInput = ""
    @FocusState private var isFocused: Bool

    var body: some View {
        ScrollView(.vertical) {
            TextField("Enter text", text: $textInput)
                .focused($isFocused)
            Button("Dismiss") {
                isFocused = false
                // 强制收起键盘
                UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
            }
        }
    }
}

方法二:使用枚举类型绑定焦点

改用枚举来标记可聚焦的控件,这种方式能更好地和ScrollView的焦点管理兼容:

struct ContentView: View {
    @State private var textInput = ""
    // 用枚举定义可聚焦的字段
    enum FocusedField { case textInput }
    @FocusState private var focusedField: FocusedField?

    var body: some View {
        ScrollView(.vertical) {
            TextField("Enter text", text: $textInput)
                // 绑定到枚举值
                .focused($focusedField, equals: .textInput)
            Button("Dismiss") {
                focusedField = nil
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者Plato

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 03:23:30