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

SwiftUI如何创建支持泛型的FocusState通用ViewModifier

SwiftUI 为FocusState实现泛型通用ViewModifier方法

改造思路

你不需要为每个焦点枚举单独写修饰器,只需要通过泛型约束适配所有符合系统要求的焦点类型即可:

  • SwiftUI 中所有用于FocusState绑定的焦点标识类型,都必须遵守Hashable协议,这是系统API的强制要求,因此泛型只需要加Hashable约束就可以覆盖所有合法的焦点枚举
  • 把修饰器和对应View扩展中写死的具体枚举类型,替换为泛型参数即可,核心收起键盘的逻辑不需要改动

改造后完整代码

// 焦点枚举仅需遵守Hashable即可被通用修饰器兼容
enum First: Hashable {
    case name
}

enum Second: Hashable {
    case lastName
}

// 泛型修饰器,F为泛型占位符,约束为Hashable
struct ResignFocusedField<F: Hashable>: ViewModifier {
    var focusField: FocusState<F?>.Binding
    
    func body(content: Content) -> some View {
        content
            .onTapGesture {
                // 任意类型的焦点值置nil都能触发收起键盘
                focusField.wrappedValue = nil
            }
    }
}

extension View {
    // 扩展方法同步适配泛型
    func resignFocusedField<F: Hashable>(_ ff: FocusState<F?>.Binding) -> some View {
        modifier(ResignFocusedField(focusField: ff))
    }
}

使用示例

改造完成后,任意符合Hashable要求的可选类型FocusState绑定,都可以直接传入修饰器使用,不需要为每个枚举单独写逻辑:

struct DemoView: View {
    @FocusState private var firstFocus: First?
    @FocusState private var secondFocus: Second?
    
    var body: some View {
        VStack(spacing: 16) {
            TextField("输入姓名", text: .constant(""))
                .focused($firstFocus, equals: .name)
            TextField("输入姓氏", text: .constant(""))
                .focused($secondFocus, equals: .lastName)
        }
        // 两种不同枚举类型的FocusState都可以正常适配
        .resignFocusedField($firstFocus)
        .resignFocusedField($secondFocus)
    }
}

注意:如果你的焦点枚举包含关联值,需要手动实现Hashable协议的对应方法,只要满足Hashable约束就可以正常使用该通用修饰器。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 15:48:16