Swift UI Custom Segmented Control

Ivan Garcia
4 min readAug 17, 2020

--

Last week I published a social network application created using Swift-UI. For this post, I’m going to elaborate on the custom segmented control that I implemented.

Just before we start, a Segmented Control it’s a UIComponent that is composed of 2 or more segments. Segments can contain images, text, buttons etc. And each of the segments allows users to select different options. Each of the options should trigger a different behavior.

The image below shows the custom segmented control including 3 different segments; “Popular”, “New” and “Follow”. By default, the custom segmented control selects the first option which is “Popular”, but the user can select the other 3 options and different behaviours will occur.

Now that we understand what’s a Segmented Control, let’s get into the code…

To get started, you can find the Source Code here

Inside the project, you will find a folder named SementedControl which contains the class named SegmentedControlView.Swfit

The code below shows the struct named SegmentedControlView that conforms the View Protocol. There is also an array of Segment named segments(a struct that contains the Id of the segment and the segment name to be displayed). Every time the SegmentedControl is created, you will need to specify the array of segments. Since it is dynamic, you can create the segmented control with N number of segments.

struct Segment: Identifiable {var id: Intvar segmentName: String}struct SegmentedControlView: View {@Binding var selected : Intvar segments: [Segment]

Binding

You can also find a Binding var named selected, it is an integer. Using Binding will let us mutate the value inside the view and it can be updated or retrieved in real-time elsewhere, even outside the context of the SegmentedControlView. Binding it’s a really powerful tool that I found for communicating the state of a Custom UI View with any other View or Element of the App.

In addition, this means that every time you are using the custom segmented control, you will need to send the Binding Var as a parameter, the following snippet shows how the SegmentedControlView is created inside a different View named ProfileView.

@State var selected = 0SegmentedControlView(selected: self.$selected, segments: [Segment(id: 0, segmentName: "Popular"), Segment(id: 1, segmentName: "New"), Segment(id: 2, segmentName: "Follow")])

State

The State var shown above, also named selected helps us to read the property selected inside the PostsTableView. In other words, everytime the Binding value it’s updated from the SegmentedControlView, it updates and displays the correct selection from the User inside the context of the PostsTableView.

For example, right now we have 3 options from the SegmentedControlView displayed on the PostsTableView: “Popular”, “New” and “Follow”. The PostsTableView is creating a SegmentedControlview with those 3 options. The State var from the PostsTableView is modifying the value of the Binding SegmentedControlView, so every time an option is tapped, the Binding var from the SegmentedControlView gets notified and the selected option changes.

As a matter of fact, a State value knows the context inside a single view in this case the PostsTableView and Binding allow us to communicate our values with different views for this case the SegmentedControlView.

UICustom Component

Now that we reviewed how the Binding and State variables are used, we can proceed with the rest of the UI implementation.

To begin with, I used a HStack, since our segmented control is a horizontal View. Then I used a ForEach which is going to iterate through the list of segments, and for each of the segments it is going to create a Button.

The Button it’s simply composed of a Text that comes from the segmentName.

Consequently, the button has an action, every time the button is tapped, it saves the selected option from the segment Id.

The button includes a foregroundColor attribute that based on the selection it will color either Black if the option is selected or gray if it isn’t.

var body: some View {    HStack {        ForEach(segments) { segment in            Button(action: {                self.selected = segment.id            })            {                VStack {                    Text(segment.segmentName)                        .padding(.horizontal, 5)                        .padding(.vertical, 0)                        .font(.custom("HelveticaNeue-Medium", size: 16))                }            }.foregroundColor(self.selected == segment.id ? .black : .gray)        }   }.padding(20)        .clipShape(Capsule())        .animation(.default)
}

To sum up, this segmented control can be used for showing different options to the user using a horizontal distribution, but of course it can be modified and not only use a simple button as an option but also include Text, Images, animations, etc.

--

--