How to change SwiftUI Segmented Control Appearance

DevTechie Inc
Dec 7, 2022


Photo by Artur Voznenko on Unsplash

SwiftUI PickerView provides an easy way to create segmented control by simply setting pickerStyle to segmentedvalue.

In this article, we will customize appearance of segmented view to match theme of our app.

We will start by creating a custom view which will take binding parameter for current selection index along with the possible selection values which will be displayed in segmented view.

struct CustomSegmentedView: View {
    
    @Binding var currentIndex: Int
    var selections: [String]
    
}
Next, we will add initializer to set these binding values:

init(_ currentIndex: Binding<Int>, selections: [String]) {
    self._currentIndex = currentIndex
    self.selections = selections
}
Let’s add body to the custom view. We will add a Picker and will bind selection parameter to currentIndex binding value. For Picker’s body, we will iterate over all the values in selections parameter as shown below. Lastly, we will set pickerStyle to segmented

var body: some View {
        VStack {
            Picker("", selection: $currentIndex) {
                ForEach(selections.indices, id: \.self) { index in
                    Text(selections[index])
                    .tag(index)
                    .foregroundColor(Color.blue)
            }
         }
        .pickerStyle(.segmented)
    }
    .padding()
}
Let’s create a View, which will use this newly created segmented control:

struct CustomSegmentedViewUse: View {
    @State private var selectedIndex = 0
    private var selections =  ["SwiftUI", "iOS", "UIKit", "Swift", "ML"]
    var body: some View {
        NavigationStack {
            VStack {
                CustomSegmentedView($selectedIndex, selections: selections)
                Text("Selected: \(selections[selectedIndex])")
                Spacer()
            }
            .navigationTitle("DevTechie")
        }
    }
}
Build and run:

If we want to change text color, applying tintColor or accentColor will not work.

struct CustomSegmentedView: View {
    
    @Binding var currentIndex: Int
    var selections: [String]
    
    init(_ currentIndex: Binding<Int>, selections: [String]) {
        self._currentIndex = currentIndex
        self.selections = selections
    }
    
    var body: some View {
        VStack {
            Picker("", selection: $currentIndex) {
                ForEach(selections.indices, id: \.self) { index in
                    Text(selections[index])
                        .tag(index)
                        .foregroundColor(Color.blue)
                }
            }
            .pickerStyle(.segmented)
            .tint(.orange)
        }
        .padding()
    }
}
Let’s take an alternate approach. Since Picker is backed by UISegmentControl, if we set appearance for UISegmentedControl, it should be able to take care of our text customization.

We will set following properties in our custom view’s initializer.

UISegmentedControl.appearance().selectedSegmentTintColor = .orange
UISegmentedControl.appearance().backgroundColor =
UIColor(Color.orange.opacity(0.3))
UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: UIColor(Color.primary)], for: .selected)
UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: UIColor(Color.secondary)], for: .normal)
Complete custom view will look like this:

struct CustomSegmentedView: View {
    
    @Binding var currentIndex: Int
    var selections: [String]
    
    init(_ currentIndex: Binding<Int>, selections: [String]) {
        self._currentIndex = currentIndex
        self.selections = selections
        UISegmentedControl.appearance().selectedSegmentTintColor = .orange
        UISegmentedControl.appearance().backgroundColor =
        UIColor(Color.orange.opacity(0.3))
        UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: UIColor(Color.primary)], for: .selected)
        UISegmentedControl.appearance().setTitleTextAttributes([.foregroundColor: UIColor(Color.secondary)], for: .normal)
    }
    
    var body: some View {
        VStack {
            Picker("", selection: $currentIndex) {
                ForEach(selections.indices, id: \.self) { index in
                    Text(selections[index])
                        .tag(index)
                        .foregroundColor(Color.blue)
                }
            }
            .pickerStyle(.segmented)
            .tint(.orange)
        }
        .padding()
    }
}
Build and run:

With that we have reached the end of this article. Thank you once again for reading. Don’t forget to follow 😍. Also subscribe our newsletter at https://www.devtechie.com