SwiftUI中包装的UITextField(decimal键盘)如何无额外按钮收起键盘
问题根因
你给VStack添加的全局点击手势默认会拦截所有点击事件:点击UITextField时,手势会先触发执行resignFirstResponder,输入框还没来得及成为第一响应者就被取消,自然无法唤起键盘。
解决方案(兼容全iOS版本,无需额外添加按钮)
核心逻辑是给点击手势添加cancelsTouchesInView = false配置,让手势不拦截子视图的触摸事件,点击输入框时优先触发激活逻辑,点击空白区域才触发键盘收起。
第一步:添加View扩展
extension View { func dismissKeyboardOnTapBlank() -> some View { self.background(TapGestureView { UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) }) } } fileprivate struct TapGestureView: UIViewRepresentable { let onTap: () -> Void func makeUIView(context: Context) -> UIView { let view = UIView() let tapGesture = UITapGestureRecognizer(target: context.coordinator, action: #selector(Coordinator.handleTap)) tapGesture.cancelsTouchesInView = false // 核心配置:不拦截子视图点击 view.addGestureRecognizer(tapGesture) return view } func updateUIView(_ uiView: UIView, context: Context) { context.coordinator.onTap = onTap } func makeCoordinator() -> Coordinator { Coordinator(onTap: onTap) } class Coordinator: NSObject { var onTap: () -> Void init(onTap: @escaping () -> Void) { self.onTap = onTap } @objc func handleTap() { onTap() } } }
第二步:替换原有VStack的点击逻辑
struct ContentView: View { @State var viewModel: ViewModel var body: some View { VStack { CustomTextView($viewModel.parameter) /// 其他视图 } .dismissKeyboardOnTapBlank() } }
iOS 16+简化方案
如果你的项目最低适配iOS 16,可以直接使用系统提供的键盘关闭环境变量,无需自定义封装:
struct ContentView: View { @State var viewModel: ViewModel @Environment(\.dismissKeyboard) private var dismissKeyboard var body: some View { VStack { CustomTextView($viewModel.parameter) /// 其他视图 } .onTapGesture { dismissKeyboard() } } }
内容的提问来源于stack exchange,提问作者Joey Nash
相关产品推荐
相关产品推荐

