iOS 13 UISegmentedControl: 3 important changes

Rostyslav Dovhaliuk
3 min readSep 14, 2019

iOS 13 brought quite a list of new features: SwiftUI, Combine, Dark Mode, RealityKit, iPad OS, etc. But several things were left almost unnoticed. Among them is a new appearance of some UIKit components. UISegmentedControl alongside with UISwitch, UIStepper, and UISlider got a new look.

Unfortunately, in the case of UISegmentedControl, those changes caused several issues which I describe next.

1. Tint color does not work anymore

The “tintColor” property introduced in iOS 7 allowed to change the appearance of UISegmentedControl.

Starting with iOS 13 “tintColor” does nothing. No matter what color you will assign, the appearance of UISegmentedControl won’t change. To make things even more unintuitive, Apple did not mark this property as deprecated. To give us at least some way to customize colors of UISegmentedControl besides the “backgroundColor” Apple introduced a new property called “selectedSegmentTintColor”. Using this property we can change the color of sliding control.

2. Default background images

While trying to pick a good background color for segmented controls in my app I noticed that the color I saw was a bit dull. After inspecting the view hierarchy, I found out that when custom background images are not set, UISegmentedControl uses some default images.

The fill color of those images can be replicated with black color with 6% opacity. What’s interesting is that we can’t get access to default background image as “backgroundImage(for: .normal, barMetrics: .default)” method returns nil in this case. What’s even worse is that if we set an empty background image (UIImage(), or any image technically) the white image with shadow beneath the sliding control disappears making resulting segmented control unusable.

Such behavior makes it impossible to use some pure background colors, e.g. white. Sure, we can assign it, but in the end, it will appear slightly gray due to blending with default background images.

3. Default rounded corners

Another problem arises when background images that cover all frame of segmented control are used. Starting with iOS 13 a corner radius is set no matter if custom background images are used or not which leads to clipped corners:

Fortunately, this issue can be fixed using the custom subclass of UISegmentedControl with overridden “layoutSubviews” method:

class SquareSegmentedControl: UISegmentedControl {
override func layoutSubviews() {
super.layoutSubviews()
layer.cornerRadius = 0
}
}

Final thoughts

Overall I have mixed feelings about an update of UISegmentedControl in this iOS release. Sure the new look is interesting, but it may force us to adapt the design of other sections of our apps for them to look more natural alongside new UISegmentedControl, and there is no way to get complete iOS 12 appearance back to win some additional time necessary for app redesign.

There is a way to get partial iOS 12 style back, described at https://stackoverflow.com/a/56458794. But it will only work for solid color backgrounds, because in iOS 12 you could see the background view through the text of selected segment or uncolored portion of the unselected segment.

If you enjoyed this post, please check out my app in the AppStore. That’s all, thanks for reading!

--

--