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
相关产品推荐
相关产品推荐

