I’ve been working on a project and I wanted the neat “button bar-style” design for my
UISegmentedControl, where there
are no borders around the segments and there’s a small bar below the selected segment which moves when you choose a new
segment. I found a couple of really good third-party projects that handled this, but I had some trouble with them and decided
to try doing it myself. Just a disclaimer, this is one way of doing it; I’m using auto layout constraints, building
the views programatically, and doing all of my theming inline for the purposes of simplicity.
I’m doing this in a Swift playground, so let’s start with the basics by creating a new
UIView and adding a
to it with three segments. Also to note, the way I’m building out my constraints will assume all segments are of equal length. If
not, the button bar at the bottom of the selected segment might end up being too wide or not wide enough for the segment it’s under.
The playground live view shows us our basic
UISegmentedControl. Don’t forget to append the
isActive property to each of the auto layout
constraints with a value of
true or they won’t work.
Colors, Fonts, and Borders Oh My!
Next, let’s remove the
tintColor. When the
tintColor is removed, the borders and the selected segment background color
will also disappear.
If you look at the live view, since we removed the
UISegmentControl has briefly “disappeared” since everything is now a clear color.
To bring back the labels, let’s change the font and text color of both the selected segment and non-selected segments.
Almost there! Now we have to add a bar below the selected segment.
Adding the Selected Segment Bar
The button bar will be a simple
UIView with a
backgroundColor matching the color of the selected segment’s font color. This can obviously be different,
but I’m choosing to make both the selected segment font and the button bar orange. Add these lines after the segmented control’s
Next, add the
buttonBar as a subview to the container view below the
addSubview call for the
Finally, we need to give the button bar a width, height, and position. Add these constraints below the
As the last comment says, we need the width of the button bar to be the width of the
segmentedControl divided by the number of segments. This guarantees
the button bar width will exactly match the width of a single segment, again assuming all segments have equal width.
The initial view is now complete! As a final step, we need to have our button bar move to the selected segment whenever it changes.
Animating the Button Bar
When the selected segment changes, the segmented control needs to call a function that will handle the transition of the button bar’s position on the x-axis
so it winds up underneath the selected segment. We have to jump through a couple hoops since this is a Swift playground, so below your
create a new
Responder class and instantiate it to a varible. Add a function definition to the
Responder class, then add a callback to the
variable to fire when the
segmentedControl’s value changes.
Be sure to pass in the
sender as an argument to the function of type
UISegmentedControl since we need access to it when the function
is called. The last piece of the puzzle is updating the
buttonBar’s value on the x-axis inside the function so it will move under the
To get the correct position on the x-axis, divide the
segmentedControl’s frame width by the
numberOfSegments, then multiply that by the
Voila! We have our animated button bar.
I hope this post has been informative as a DIY solution to something you’ve probably seen in a lot of libraries or on a lot of iOS applications. From here, you can
hook up the
UISegmentedControl to a
UIScrollView as a way of moving between segmented content. You can find the playground code
here as a GitHub Gist, and good luck with your iOS development!