iosswiftui

How to change thumb color of Toggle view in SwiftUI?


I am aware that I can change the background color of a Toggle using .tint(). However, my toggle background can be yellow or similar (light) colors, which doesn’t look good with the default white thumb.

Here is how it looks:

yellow toggle with white thumb

Off mode looks good though, so that is no issue:

off mode picture

How can I change the thumb color in SwiftUI so that it looks good with different background colors?


Solution

  • For now, you can only change the thumb color through UISwitch.thumbTintColor. Here is a modified version of this answer that allows you to pass in a color for thumbTintColor, in addition to onTintColor.

    public struct ColoredSwitch<Label>: View where Label: View {
    
        @Binding var isOn: Bool
        var thumbTintColor: Color
        var onTintColor: Color
    
        var label: Label
    
        public init(isOn: Binding<Bool>, thumbTintColor: Color, onTintColor: Color, @ViewBuilder label: () -> Label) {
            self._isOn = isOn
            self.label = label()
            self.thumbTintColor = thumbTintColor
            self.onTintColor = onTintColor
        }
    
        public var body: some View {
            LabeledContent {
                UISwitchWrapper(isOn: $isOn, thumbTintColor: thumbTintColor, onTintColor: onTintColor)
            } label: {
                label
            }
        }
    }
    
    struct UISwitchWrapper: UIViewRepresentable {
    
        @Binding var isOn: Bool
        var thumbTintColor: Color
        var onTintColor: Color
    
        public func makeUIView(context: Context) -> UISwitch {
            let uiSwitch = UISwitch()
            uiSwitch.addTarget(
                context.coordinator,
                action: #selector(Coordinator.valueChanged(_:)),
                for: .valueChanged
            )
            return uiSwitch
        }
    
        public func updateUIView(_ uiView: UISwitch, context: Context) {
            uiView.setOn(isOn, animated: !context.transaction.disablesAnimations)
            uiView.thumbTintColor = UIColor(thumbTintColor)
            uiView.onTintColor = UIColor(onTintColor)
            context.coordinator.parent = self
        }
    
        public func makeCoordinator() -> Coordinator {
            Coordinator(self)
        }
    
        @MainActor
        public class Coordinator: NSObject {
    
            var parent: UISwitchWrapper
    
            init(_ parent: UISwitchWrapper) {
                self.parent = parent
            }
    
            @objc
            func valueChanged(_ sender: UISwitch) {
                parent.isOn = sender.isOn
            }
        }
    }
    

    Example usage:

    @State private var isOn = false
    var body: some View {
        ColoredSwitch(isOn: $isOn, thumbTintColor: .blue, onTintColor: .yellow) {
            Text("Some Label")
        }
    }