Toggle(Switch Control) in SwiftUI

DevTechie Inc
Jun 11

Photo by Arthur Mazi on Unsplash

Toggle in SwiftUI is same as our good old UIKit’s Switch control. Toggle control can turn on or off. Toggle needs a binding variable which updates as you toggle the control view’s state.

Toggle control comes with a label and switch. Let’s start with a simple example. In this example, we will create a State variable called agreeToTerms and initialize it with false value. We will bind this variable to Toggle by passing binding value in isOn parameter. As shown below:

struct ToggleExample: View {
    @State private var agreeToTerms = false
    var body: some View {
        VStack {
            Text("DevTechie Terms and Conditions")
            Toggle("Agree", isOn: $agreeToTerms)
        }
        .padding()
    }
}
You can observe change on binding variable at other places. For example, let’s say, your app requires users to agree on terms and conditions, in this case toggle on represents that user has agreed to the terms and is ready to move forward. We will observe change in toggle’s binding value and enable/disable continue button based on the state of toggle as shown below:

struct ToggleExample: View {
    @State private var agreeToTerms = false
    var body: some View {
        VStack {
            Text("DevTechie Terms and Conditions")
            Toggle("Agree", isOn: $agreeToTerms)
            Button(action: {}) {
                HStack {
                    Text("Continue")
                    Image(systemName: "chevron.right.circle")
                }
                .padding()
                .background(.blue, in: Capsule())
                .foregroundColor(agreeToTerms ? .primary : .gray)
            }
            .disabled(!agreeToTerms)
        }
        .padding()
    }
}
Labels hidden
labelsHidden modifier can be used with Toggle as well to hide the label so you can give your own custom look for the toggle label.

struct ToggleExample: View {
    @State private var agreeToTerms = false
    var body: some View {
        VStack {
            Text("DevTechie Terms and Conditions")
                .padding(.bottom)
            VStack {
                Text("Agree?")
                    .font(.title3.bold())
                Toggle("Agree", isOn: $agreeToTerms)
                    .labelsHidden()
            }
            Button(action: {}) {
                HStack {
                    Text("Continue")
                    Image(systemName: "chevron.right.circle")
                }
                .padding()
                .background(.blue, in: Capsule())
                .foregroundColor(agreeToTerms ? .primary : .gray)
            }
            .disabled(!agreeToTerms)
        }
        .padding()
    }
}
Styling the Toggle
Toggle can be styled in a few ways, you have option to apply ToggleStyle modifier to apply some of the predefined styles. For example, starting iOS 15+ you can turn your default Toggle switch into a toggle button:

struct ToggleExample: View {
    @State private var agreeToTerms = false
    var body: some View {
        VStack {
            Text("DevTechie Terms and Conditions")
                .padding(.bottom)
            VStack {
                Text("Agree?")
                    .font(.title3.bold())
                Toggle(isOn: $agreeToTerms) {
                    Image(systemName: agreeToTerms ? "hand.thumbsup.fill" : "hand.thumbsdown.fill")
                }
                    .labelsHidden()
                    .toggleStyle(.button)
            }
            Button(action: {}) {
                HStack {
                    Text("Continue")
                    Image(systemName: "chevron.right.circle")
                }
                .padding()
                .background(.blue, in: Capsule())
                .foregroundColor(agreeToTerms ? .primary : .gray)
            }
            .disabled(!agreeToTerms)
        }
        .padding()
    }
}
You can also apply tint to the Toggle as shown below:

struct ToggleExample: View {
    @State private var agreeToTerms = false
    var body: some View {
        VStack {
            Text("DevTechie Terms and Conditions")
                .padding(.bottom)
            VStack {
                Text("Agree?")
                    .font(.title3.bold())
                Toggle(isOn: $agreeToTerms) {
                    Image(systemName: agreeToTerms ? "hand.thumbsup.fill" : "hand.thumbsdown.fill")
                }
                    .labelsHidden()
                    .toggleStyle(.button)
                    .tint(.green)
            }
            Button(action: {}) {
                HStack {
                    Text("Continue")
                    Image(systemName: "chevron.right.circle")
                }
                .padding()
                .background(.blue, in: Capsule())
                .foregroundColor(agreeToTerms ? .primary : .gray)
            }
            .disabled(!agreeToTerms)
        }
        .padding()
    }
}
Custom Toggle View
If you are looking for further customization then you can build your own style by extending ToggleStyle protocol, as shown below:

struct ToggleExample: View {
    @State private var agreeToTerms = false
    var body: some View {
        VStack {
            Text("DevTechie Terms and Conditions")
                .padding(.bottom)
            VStack {
                Text("Agree?")
                    .font(.title3.bold())
                Toggle(isOn: $agreeToTerms) {
                    Image(systemName: agreeToTerms ? "hand.thumbsup.fill" : "hand.thumbsdown.fill")
                }
                .toggleStyle(CustomToggle())
                    .labelsHidden()
                    .tint(.green)
            }
            Button(action: {}) {
                HStack {
                    Text("Continue")
                    Image(systemName: "chevron.right.circle")
                }
                .padding()
                .background(.blue, in: Capsule())
                .foregroundColor(agreeToTerms ? .primary : .gray)
            }
            .disabled(!agreeToTerms)
        }
        .padding()
    }
}struct CustomToggle: ToggleStyle {
    let width: CGFloat = 50
    
    func makeBody(configuration: Self.Configuration) -> some View {
        HStack {
            configuration.label
            
            ZStack(alignment: configuration.isOn ? .trailing : .leading) {
                Capsule()
                    .frame(width: width, height: width / 2)
                    .foregroundColor(configuration.isOn ? .green : .red)
                
                Capsule()
                    .frame(width: (width / 2) - 4, height: width / 2 - 6)
                    .padding(4)
                    .foregroundColor(.white)
                    .onTapGesture {
                        withAnimation {
                            configuration.$isOn.wrappedValue.toggle()
                        }
                    }
            }
        }
    }
}
With that we have reached the end of this article. Thank you once again for reading. Don’t forget to subscribe to our weekly newsletter at https://www.devtechie.com