How to change the colors of a segment in a UISegmentedControl in iOS 13?
As of iOS 13b3, there is now a selectedSegmentTintColor
on UISegmentedControl
.
To change the overall color of the segmented control use its backgroundColor
.
To change the color of the selected segment use selectedSegmentTintColor
.
To change the color/font of the unselected segment titles, use setTitleTextAttributes
with a state of .normal
/UIControlStateNormal
.
To change the color/font of the selected segment titles, use setTitleTextAttributes
with a state of .selected
/UIControlStateSelected
.
If you create a segmented control with images, if the images are created as template images, then the segmented control's tintColor
will be used to color the images. But this has a problem. If you set the tintColor
to the same color as selectedSegmentTintColor
then the image won't be visible in the selected segment. If you set the tintColor
to the same color as backgroundColor
, then the images on the unselected segments won't be visible. This means your segmented control with images must use 3 different colors for everything to be visible. Or you can use non-template images and not set the tintColor
.
Under iOS 12 or earlier, simply set the segmented control's tintColor
or rely on the app's overall tint color.
UISegmentedControl iOS 13 clear color
Here's a way to replicate that plain segmented control in iOS 13:
import UIKit
import PlaygroundSupport
class PlainSegmentedControl: UISegmentedControl {
override init(items: [Any]?) {
super.init(items: items)
setup()
}
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// Used for the unselected labels
override var tintColor: UIColor! {
didSet {
setTitleTextAttributes([.foregroundColor: tintColor!, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 13, weight: .regular)], for: .normal)
}
}
// Used for the selected label
override var selectedSegmentTintColor: UIColor? {
didSet {
setTitleTextAttributes([.foregroundColor: selectedSegmentTintColor ?? tintColor!, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 13, weight: .regular)], for: .selected)
}
}
private func setup() {
backgroundColor = .clear
// Use a clear image for the background and the dividers
let tintColorImage = UIImage(color: .clear, size: CGSize(width: 1, height: 32))
setBackgroundImage(tintColorImage, for: .normal, barMetrics: .default)
setDividerImage(tintColorImage, forLeftSegmentState: .normal, rightSegmentState: .normal, barMetrics: .default)
// Set some default label colors
setTitleTextAttributes([.foregroundColor: UIColor.black, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 13, weight: .regular)], for: .normal)
setTitleTextAttributes([.foregroundColor: tintColor!, NSAttributedString.Key.font: UIFont.systemFont(ofSize: 13, weight: .regular)], for: .selected)
}
}
Here's some test code to put in a playground:
// Create a dark green view as a test background
let bg = UIView(frame: CGRect(x: 0, y: 0, width: 400, height: 100))
bg.backgroundColor = UIColor(red: 0.224, green: 0.408, blue: 0.467, alpha: 1)
// The plain segmented control
let seg = PlainSegmentedControl(items: ["Number One", "Number Two", "Number Three"])
seg.tintColor = .white
seg.selectedSegmentTintColor = .green
seg.selectedSegmentIndex = 0
bg.addSubview(seg)
PlaygroundPage.current.liveView = bg
Here's the UIImage
extension to create a sized image from a color:
extension UIImage {
convenience init(color: UIColor, size: CGSize) {
UIGraphicsBeginImageContextWithOptions(size, false, 1)
color.set()
let ctx = UIGraphicsGetCurrentContext()!
ctx.fill(CGRect(origin: .zero, size: size))
let image = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
self.init(data: image.pngData()!)!
}
}
Segmented Controller background grey after iOS13
Try this:
if (@available(iOS 13.0, *)) {
self.segmentedControl.selectedSegmentTintColor = UIColor.redColor;
self.segmentedControl.layer.backgroundColor = UIColor.greenColor.CGColor;
}
.selectedSegmentTintColor
defines the selected button color and .layer.backgroundColor
the color for the whole UISegmentedControl background.
This is the result:
EDIT
It turns out this won't work for background clear or white, since on iOS 13 a sort of background image is added on the background and dividers of the segmented control:
A workaroud is create an image from color with UIGraphicsGetImageFromCurrentImageContext
. The code looks like this:
- (void)viewDidLoad {
[super viewDidLoad];
if (@available(iOS 13.0, *)) {
self.segmentedControl.selectedSegmentTintColor = UIColor.redColor;
self.segmentedControl.layer.backgroundColor = UIColor.clearColor.CGColor;
[self customizeSegmentedControlWithColor: UIColor.whiteColor];
}
}
- (void)customizeSegmentedControlWithColor:(UIColor *)color {
UIImage *tintColorImage = [self imageWithColor: color];
[self.segmentedControl setBackgroundImage:[self imageWithColor:self.segmentedControl.backgroundColor ? self.segmentedControl.backgroundColor : [UIColor clearColor]] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
[self.segmentedControl setBackgroundImage:tintColorImage forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
[self.segmentedControl setBackgroundImage:[self imageWithColor:[color colorWithAlphaComponent:0.2]] forState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault];
[self.segmentedControl setBackgroundImage:tintColorImage forState:UIControlStateSelected|UIControlStateSelected barMetrics:UIBarMetricsDefault];
[self.segmentedControl setDividerImage:tintColorImage forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
self.segmentedControl.layer.borderWidth = 1;
self.segmentedControl.layer.borderColor = [color CGColor];
}
- (UIImage *)imageWithColor: (UIColor *)color {
CGRect rect = CGRectMake(0.0f, 0.0f, 1.0f, 1.0f);
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [color CGColor]);
CGContextFillRect(context, rect);
UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return theImage;
}
Check more about it here.
This is the result for background view with color and segmented control white:
And is the result for background view white and segmented control with color:
How to set backgroundColor of UISegmentedControl to white in iOS 13
I have the same issue and there is no cool way to resolve it. So I did this small workaround. I dont like it and I am not proud of it, but it works.
func fixBackgroundSegmentControl( _ segmentControl: UISegmentedControl){
if #available(iOS 13.0, *) {
//just to be sure it is full loaded
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
for i in 0...(segmentControl.numberOfSegments-1) {
let backgroundSegmentView = segmentControl.subviews[i]
//it is not enogh changing the background color. It has some kind of shadow layer
backgroundSegmentView.isHidden = true
}
}
}
}
UIControlSegment background color is not transparent anymore on iOS13
thanks @Maulik Pandya for the answer,
I have improve your answer little bit.
extension UISegmentedControl {
func clearBG() {
let clearImage = UIImage().imageWithColor(color: .clear)
setBackgroundImage(clearImage, for: .normal, barMetrics: .default)
setBackgroundImage(clearImage, for: .selected, barMetrics: .default)
setDividerImage(clearImage, forLeftSegmentState: .normal, rightSegmentState: .normal, barMetrics: .default)
}
}
public extension UIImage {
public func imageWithColor(color: UIColor) -> UIImage {
let rect = CGRect(x: 0.0, y: 0.0, width: 1.0, height: 1.0)
UIGraphicsBeginImageContext(rect.size)
guard let context = UIGraphicsGetCurrentContext() else { return UIImage()}
context.setFillColor(color.cgColor)
context.fill(rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image!
}
}
Related Topics
iOS - Using Storyboard and Autolayout to Center the Uiscrollview
Bypass Code Signing with Xcode 6
Swift - How to Open Specific View Controller When Push Notification Received
Today Extension View Flashes When Redrawing
iOS - Spritekit - How to Calculate the Distance Between Two Nodes
Get Created Date and Last Login Date from Firuser with Firebase 3
Problems Adding Custom Activity to Uiactivitycontroller
Odd Property Declaration Syntax Containing Angular Brackets <>
How to Remove Black Edge on Uiimageview with Rounded Corners and a Border Width
Xcode5:The App References Non-Public Selectors in Payload/<Appname>.App/<Appname>: Setattribution:
What Does $0 Represent in Closures in Swift
Undefined Symbols for Architecture Armv7 for Cocoapods Libraries
Apns Push Notifications Not Working on Production
Programmatically Detect Dark Mode in Swiftui to Display Appropriate Image
Safari Web View Opening When Logging to Fb Through iOS 9
How to Make a Conical Gradient in iOS Using Core Graphics/Quartz 2D