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

如何在可复用TextField组合视图中检测FocusState变化

实现方案

核心逻辑是把焦点判断封装在自定义组件内部,不需要依赖外部传入的焦点枚举值,利用SwiftUI焦点系统的自动透传、多绑定同步特性实现效果。

底层逻辑说明

SwiftUI的焦点系统会沿视图树自动向下匹配可聚焦控件(比如TextField),外层添加的.focused修饰符不会被中间的容器视图拦截,会自动绑定到内部符合要求的可聚焦子视图上,这也是你把TextField包在自定义容器里,外部焦点设置依然生效的原因。
同时系统支持同一个可聚焦控件的焦点状态同步到多个@FocusState绑定上,外部的焦点枚举绑定、内部的焦点判断绑定不会产生冲突。

具体实现代码

你只需要在自定义的MyCustomTextField内部新增一个私有的布尔类型@FocusState,绑定到内部的TextField上,直接用这个状态控制下划线颜色即可,外部调用代码不需要做任何修改。

struct MyCustomTextField: View {
    let placeholder: String
    @Binding var text: String
    // 内部私有焦点状态,自动监听当前输入框的焦点情况
    @FocusState private var isFocused: Bool
    
    var body: some View {
        VStack(spacing: 8) {
            TextField(placeholder, text: $text)
                .focused($isFocused) // 绑定内部焦点状态
                .padding(.horizontal)
            
            // 原有下划线逻辑,直接使用内部焦点状态判断颜色
            Rectangle()
                .fill(isFocused ? Color.blue : Color.gray)
                .frame(maxWidth: .infinity, minHeight: 2, maxHeight: 2)
                .padding(.horizontal)
        }
    }
}

不要把外部的焦点枚举作为参数传入自定义组件做判断,这种方式会让组件和业务层的焦点定义强耦合,失去复用性,上述内部封装的方案完全不需要感知外部的焦点逻辑。

外部调用方式

你之前写的父视图代码完全不需要调整,和使用原生TextField的逻辑完全一致:

struct ContentView: View {
    private enum FocusedField {
        case first
        case second
        case third
    }
    @FocusState private var focusedField: FocusedField?
    @State private var firstText = ""
    @State private var secondText = ""
    @State private var thirdText = ""
    
    var body: some View {
        VStack(spacing: 24) {
            MyCustomTextField(placeholder: "第一个输入框", text: $firstText)
                .focused($focusedField, equals: .first)
            
            MyCustomTextField(placeholder: "第二个输入框", text: $secondText)
                .focused($focusedField, equals: .second)
            
            MyCustomTextField(placeholder: "第三个输入框", text: $thirdText)
                .focused($focusedField, equals: .third)
        }
    }
}

扩展能力

如果需要在输入框获焦/失焦时触发额外逻辑,直接在自定义组件内部监听isFocused的变化即可,不需要外部做任何处理:

// 加在MyCustomTextField的VStack下
.onChange(of: isFocused) { focused in
    if focused {
        // 获焦时的自定义逻辑,比如埋点、触发动画
    } else {
        // 失焦时的自定义逻辑,比如输入格式校验
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 07:03:17