skip to Main Content

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

2

Answers


  1. Chosen as BEST ANSWER

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

  2. 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)
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search