如何在SwiftUI中使用开关来禁用TextField?

4
当使用SwiftUI的Toggle时,如何正确禁用TextField?如果我们禁用一个已输入一些值的TextField,下面这个简单的示例会在控制台中引发警告,删除也无法解决这个问题。
struct ContentView: View {
@State var isToogleOn = false
@State var textFieldValue = ""

var body: some View {
    HStack {
        TextField("Placeholder", text: $textFieldValue)
            .disabled(!isToogleOn)
        Toggle("Activate textField", isOn: $isToogleOn)
        }
    }
}

文本字段关闭时的警告:

=== 属性图:通过属性 160396 检测到循环 === 2022-01-08 15:27:46.182588+0100 CrochetIo[15460:1558507] [SwiftUI] 在视图更新期间修改状态,这将导致未定义的行为

2个回答

4
@Asperi提供的原因是正确的,但我建议另外一种解决方案。当关闭Toogle时,让我们取消TextField上的焦点,然后再禁用它。
    @State var isToogleOn = false
    @State var textFieldIsDisabled = false
    @State var textFieldValue = ""
    
    @FocusState private var focusField: Field?
    
    var body: some View {
        HStack {
            TextField("Placeholde", text: $textFieldValue)
                .focused($focusField, equals: .textField1)
                .disabled(textFieldIsDisabled)
            Toggle("Activate textField", isOn: $isToogleOn)
                .onChange(of: isToogleOn) { newValue in
                    focusField = nil
                    textFieldIsDisabled = !newValue
                }
        }
    }
}

0

实际上这是苹果的日志,所以我们不应该关心它们,但如果它们打扰到您,那么有可能解决这个问题,因为它们是由于在禁用期间TextField仍然处于焦点状态而发布的。

可能的方法是在注入预设副作用的切换上使用代理绑定。

已在Xcode 13.2 / iOS 15.2上进行了测试。

struct ContentViewTestToggleText: View {
    @State var isToogleOn = false
    @State var textFieldValue = ""

    var body: some View {
        HStack {
            TextField("Placeholder", text: $textFieldValue)
                .disabled(!isToogleOn)

            let onToggle = Binding(
                get: { self.isToogleOn },
                set: {
                    if !$0 {
                        UIApplication.shared.endEditing()     // << here !!
                    }
                    
                    self.isToogleOn = $0
                }
            )
            Toggle("Activate textField", isOn: onToggle)
        }
    }
}

extension UIApplication {
    func endEditing() {
        sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接