Create a custom segmented control in SwiftUI
In this tutorial, we will see how to create a custom segment control in SwiftUI.
A segment control is like a row of buttons or tabs that lets us pick from different options. We have probably seen it before, it is a way to choose one thing from a bunch of choices. We can only pick one option at a time, and each button or segment stands for a different choice.
Create segment control
First of all, I will create a picker using the Picker
view and apply the pickerStyle()
modifier with the parameter .segmented
on the Picker
view to create a segment control.
You can use the SegmentedPickerStyle()
instead of the .segmented
style if you are using Xcode 12.
Example
import SwiftUI struct ContentView: View { // State variable to keep track of the selected color index @State private var selectedColor = 0 // Array of colors let colors = ["Red", "Blue", "Green"] var body: some View { VStack(spacing: 30) { // Picker view allowing the user to select a color Picker("Selected Color", selection: $selectedColor) { // Creating segments for each color using a ForEach loop ForEach(0..<colors.count, id: \.self) { index in // Displaying the color names as segments Text(colors[index]).tag(index) } } // Setting the picker style to segmented .pickerStyle(.segmented) // Displaying the selected color based on the index Text("Selected Color: \(colors[selectedColor])") .font(.title3) } } }
In the above program, I have declared the colors
array to store different color names like “Red,” “Blue,” and “Green.”
Inside the Picker, I used a ForEach
loop to make Text labels for each color in the array. These labels become the clickable options in the segmented control.
Then, I have stored the selected segment index in the selectedColor
variable.
I have also used a Text view to display the selected color below the segment control based on the selectedColor
variable.
Output:
Create custom segment control
Creating a custom segmented control means designing a view that will display the segmented control’s user interface.
Now, follow the steps below to create a custom segment control in SwiftUI.
Define the Custom Segmented Control View
First of all, I will define a custom struct
, this struct will represent our custom segmented control.
This struct will contain properties for the selected option index, an array of options, a base color, and a corner radius.
Example
import SwiftUI struct MySegmentedControl: View { @Binding var selectedOptionIndex: Int var options: [String] let baseColor = Color.mint let cornerRadius: CGFloat = 20 var body: some View { // Implementation of the segmented control UI } }
In the above code, I have created a custom struct
called MySegmentedControl
to represent a segmented control with customizable options and appearance.
Inside the MySegmentedControl
struct, I have used a @Binding
property to track the selected option index, an array options
to store the available options, and styling parameters such as baseColor
and cornerRadius
.
Implementation of the segmented control UI
Now, within the body
property of MySegmentedControl
, I will build the UI for the segmented control.
This is where I will create the structure and appearance of the segmented control using SwiftUI components like HStack
, Button
, and others.
Example
HStack(spacing: 10) { ForEach(options.indices, id: \.self) { index in // Create a button for each option Button(action: { // Apply animation when tapped withAnimation(.easeInOut(duration: 0.3)) { // Update the selected index when the button is tapped selectedOptionIndex = index } }) { ZStack { // Background RoundedRectangle(cornerRadius: cornerRadius) .fill(baseColor.opacity(0.2)) // Selected Highlight RoundedRectangle(cornerRadius: cornerRadius) .fill(baseColor) // Inner shape filled with base color .padding(2) // Add padding to inner shape .opacity(selectedOptionIndex == index ? 1 : 0.1) // Adjust opacity based on the selected index } .overlay( Text(options[index]) // Display the text of the option ) } } } .frame(height: 40) .cornerRadius(cornerRadius) .padding()
In the program above, I have used HStack
to create a horizontal stack to align the segments horizontally.
I heve used a Button
to represent each segment, so clicking the button would trigger the action.
Then, I have used the RoundedRectangle
shape to visualize each segment, and the selected segment is highlighted separately.
I have also covered the Text on each side with an overlay
to show the corresponding option label.
Implement the Main ContentView
Now, within the the ContentView
I will define a @State
property to track the index of the selected color and a array that will hold the available color option.
Then, within the body I will use the custom segmented control MySegmentedControl
with binding to selectedIndex
to select colors, and a Text
view to display the currently selected color.
Example
struct ContentView: View { // State variable to track the index of the selected color @State var selectedIndex = 0 // Array holding available color options let colorOptions = ["Red", "Blue", "Green"] var body: some View { VStack { // Custom segmented control to select colors MySegmentedControl(selectedOptionIndex: $selectedIndex, options: colorOptions) // Text displaying the currently selected color Text("Selected color: \(colorOptions[selectedIndex])") .font(.title2) } } }
In the above code, I have defined a @State
property called selectedIndex
to track the index of the selected color.
I have also created an array called colorOptions
to hold available color names such as “Red”, “Blue” and “Green”.
Here is the complete code below.
import SwiftUI struct MySegmentedControl: View { @Binding var selectedOptionIndex: Int var options: [String] let baseColor = Color.mint let cornerRadius: CGFloat = 20 var body: some View { HStack(spacing: 10) { ForEach(options.indices, id: \.self) { index in Button(action: { withAnimation(.easeInOut(duration: 0.3)) { selectedOptionIndex = index } }) { ZStack { RoundedRectangle(cornerRadius: cornerRadius) .fill(baseColor.opacity(0.2)) RoundedRectangle(cornerRadius: cornerRadius) .fill(baseColor) .padding(2) .opacity(selectedOptionIndex == index ? 1 : 0.1) } .overlay( Text(options[index]) ) } } } .frame(height: 40) .cornerRadius(cornerRadius) .padding() } } struct ContentView: View { @State var selectedIndex = 0 let colorOptions = ["Red", "Blue", "Green"] var body: some View { VStack { MySegmentedControl(selectedOptionIndex: $selectedIndex, options: colorOptions) Text("Selected color: \(colorOptions[selectedIndex])") .font(.title2) } } }
Output:
Leave a Reply