如何通过FocusState实现点击TextField外区域收起键盘(避免误触)
解决SwiftUI中点击TextField时键盘被意外收起的问题
你的代码核心问题在于外层视图的onTapGesture会响应所有点击事件(包括点击TextField的情况),导致focusedField被设为nil,键盘被错误收起。要解决这个问题,只需给包含TextField的内层容器添加一个空手势来拦截区域内的点击事件,避免外层手势触发:
修改后的完整代码
import SwiftUI import Foundation enum Placeholder: Hashable { case email case password var description: String { switch self { case .email: return "email" case .password: return "password" } } func nextControl() -> Placeholder { return switch self { case .email: .password case .password: .email } } } struct TextFieldObservers: View { @FocusState var focusedField: Placeholder? @State var flag: Bool = false var body: some View { VStack { VStack { CustomTextField(placeHolder: .email, description: "", focusedField: $focusedField) CustomTextField(placeHolder: .password, description: "", focusedField: $focusedField) } .background(Color.green) .onTapGesture {} // 新增:拦截内层区域的点击事件,阻止传递到外层 } .frame(maxWidth: .infinity, maxHeight: .infinity) .background(Color.red) .onTapGesture { focusedField = nil } } } struct CustomTextField: View { var placeHolder: Placeholder @State var description: String @FocusState.Binding var focusedField: Placeholder? init(placeHolder: Placeholder, description: String, focusedField: FocusState<Placeholder?>.Binding) { self.placeHolder = placeHolder self.description = description self._focusedField = focusedField } var body: some View { TextField(placeHolder.description, text: $description) .padding(.horizontal, 20) .frame(width: 300, height: 50) .background { RoundedRectangle(cornerRadius: 12) .fill(.white) } .focused($focusedField, equals: placeHolder) .submitLabel(.next) .onSubmit { focusedField = placeHolder.nextControl() } } } #Preview { TextFieldObservers() }
原理说明
- 内层VStack的空
onTapGesture会优先处理该区域内的所有点击操作(包括TextField的点击),事件被拦截后不会传递到外层视图的手势,因此focusedField不会被意外设为nil,TextField可以正常获取焦点并保持键盘显示。 - 点击红色背景的空白区域时,外层视图的
onTapGesture触发,将focusedField设为nil,键盘正常收起。 - 该方案完全基于SwiftUI的
FocusState实现,未使用任何UIKit相关方法。
内容的提问来源于stack exchange,提问作者Beast
相关产品推荐
相关产品推荐

