简体   繁体   中英

How to disable TextField with Toogle in SwiftUI?

How should TextField be properly disabled when using Toogle in swiftUI? The following simple example causes warnings in the console if we disable a TextField that has some value entered in it, deleting it doesn't fix the situation either.

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)
        }
    }
}

Warnings when textfield is switched off:

=== AttributeGraph: cycle detected through attribute 160396 === 2022-01-08 15:27:46.182588+0100 CrochetIo[15460:1558507] [SwiftUI] Modifying state during view update, this will cause undefined behavior

Actually it is Apple's logs, so we should not care about them, but if they disturb you, then it is possible to solve that, because they are posted due to TextField is still in focus during disable.

The possible approach is to use proxy binding on toggle with injected pre-set side-effect.

Tested with 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)
    }
}

The reason given by @Asperi is correct, but I would suggest other solution. When switching Toogle off, let's drop the focus on the TextField and only then disable it.

    @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
                }
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM