iosswiftswiftuiuikeyboarduikeyboardtype

SwiftUI - Toggle keyboard type (default/numeric) using Toggle switch?


I am creating an application setup screen in iOS using SwiftUI, where a user will enter a password and then confirm it. I have created a ToolbarItemGroup for my keyboard that will let the user toggle between a numeric password and a complex password using a Toggle control. I would like to be able to toggle the UIKeyboardType to match the value of the Toggle switch, as well, but I am not seeing it update as expected. Here's what my code looks like so far:

        SecureField("Master Password", text: $viewModel.password)
            .modifier(NoAutocapitalizationViewModifier())
            .padding()
            .overlay(RoundedRectangle(cornerRadius: 10.0).strokeBorder(Color.blue, style: StrokeStyle(lineWidth: 2.0)))
            .padding([.horizontal])
            .frame(maxWidth: .infinity)
            .keyboardType(viewModel.isAlphaNumeric ? .default : .numberPad)
            .toolbar {
                ToolbarItemGroup(placement: .keyboard) {
                    Spacer()
                    
                    Toggle("Complex Password", isOn: $viewModel.isAlphaNumeric)
                        .toggleStyle(.switch)
                }
            }

        SecureField("Confirm Password", text: $viewModel.confirmPassword)
            .modifier(NoAutocapitalizationViewModifier())
            .padding()
            .overlay(RoundedRectangle(cornerRadius: 10.0).strokeBorder(Color.blue, style: StrokeStyle(lineWidth: 2.0)))
            .padding([.horizontal])
            .frame(maxWidth: .infinity)
            .keyboardType(viewModel.isAlphaNumeric ? .default : .numberPad)
            .toolbar {
                ToolbarItemGroup(placement: .keyboard) {
                    Spacer()
                    
                    Toggle("Complex Password", isOn: $viewModel.isAlphaNumeric)
                        .toggleStyle(.switch)
                }
            }

As you can see, the Toggle updates a boolean value in my ViewModel object to indicate whether it is a complex password. However, I am not seeing the change reflected in the .keyboardType value whenever I change the value of the switch. If I move to the "Confirm Password" field and then move back I see the keyboard changed appropriately, but it does not happen dynamically when changing the Toggle value.

How can I get the UIKeyboardType value to change dynamically based off the value of the Toggle control?


Solution

  • The keyboard once created can be cached, so try like the following (everywhere needed):

        SecureField("Confirm Password", text: $viewModel.confirmPassword)
            .modifier(NoAutocapitalizationViewModifier())
            .padding()
            .overlay(RoundedRectangle(cornerRadius: 10.0).strokeBorder(Color.blue, style: StrokeStyle(lineWidth: 2.0)))
            .padding([.horizontal])
            .frame(maxWidth: .infinity)
            .keyboardType(viewModel.isAlphaNumeric ? .default : .numberPad)
            .toolbar {
                ToolbarItemGroup(placement: .keyboard) {
                    Spacer()
                    
                    Toggle("Complex Password", isOn: $viewModel.isAlphaNumeric)
                        .toggleStyle(.switch)
                }
            }
            .id(viewModel.isAlphaNumeric)      // << here !!