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

如何通过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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 10:28:24