Customizing the Colors of a Uisegmentedcontrol

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.

Customizing the colors of a UISegmentedControl

UISegmentedControl has a tintColor property -- this allows you to change what color the control is, but not the general "style" (the rounded, beveled shape):

segmentedControl.tintColor = [UIColor blueColor];

As for creating UIImages on the fly, you can create a CGContext, do whatever drawing you need to in that context (including strings), and then get a UIImage out of the context's CGImage:

CGContextRef drawContext = CGBitmapContextCreate(<many parameters>);
//do drawing here
CGImageRef finalImage = CGBitmapContextCreateImage(drawContext);
UIImage *cellImage = [UIImage finalImage];

Please note, that if you use code like UIView.appearance().tintColor = .myColor (or equiv. in ObjC), the effect most likely won't take place.

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
}
}
}
}

Customise font color of each segment in UISegmented Control

One idea would be to recursively traverse through segment's view hierarchy and check if you encounter a UILabel

Set up your UISegmentControl as normal

func addControl()  {
let items = ["One", "Two", "Three"]
let segmentedControl = UISegmentedControl(items: items)
segmentedControl.frame = CGRect(x: 35, y: 200, width: 250, height: 50)
segmentedControl.center = view.center
segmentedControl.selectedSegmentIndex = 1
view.addSubview(segmentedControl)

// custom function
updateSegmentTextColor(segmentedControl)
}

This function runs through the view hierarchy and set's the color of the labels

// Just for testing
func randomColor() -> UIColor
{
let red = CGFloat(arc4random_uniform(256)) / 255.0
let blue = CGFloat(arc4random_uniform(256)) / 255.0
let green = CGFloat(arc4random_uniform(256)) / 255.0

return UIColor(red: red, green: green, blue: blue, alpha: 1.0)
}

private func updateSegmentTextColor(_ rootView: UIView)
{
for subview in rootView.subviews
{
if let label = subview as? UILabel
{
// Any color you want
label.textColor = randomColor()
}

updateSegmentTextColor(subview)
}
}

The result:

Custom Different UISegmentControl Title Text Color

A couple of final notes:

  • This solution could impact other tint properties you may want to set and is useful when you want to keep the same color of the text for selected and deselected states
  • Future iOS updates and implementations of Segment Control could have an impact on how this works

Update

If you want to specify the title color for a specific segment, you could assume (gamble) that the segment control should lay out its subviews in the logical order.

I emphasized on assume because this order is not in our control and you are at the mercy of the implementation.

Infact, if you set the selected index segmentedControl.selectedSegmentIndex = 1 and if you have 4 segments, the order of laying out the subviews is 0, 2, 3, 1 so the selected segment gets added last.

What could work for your situation is as follows:

// Add a color queue to hold the colors for the 4 segments
var colorQueue: [UIColor] = [.red, .blue, .green, .orange]

private func updateSegmentTextColor(_ rootView: UIView)
{
for subview in rootView.subviews
{
if let label = subview as? UILabel,
!colorQueue.isEmpty
{
// Dequeue the front of the queue
let color = colorQueue.removeFirst()
label.textColor = color
}

updateSegmentTextColor(subview)
}
}

private func addControl() {
let items = ["One", "Two", "Three", "Four"]
let segmentedControl = UISegmentedControl(items: items)
segmentedControl.frame = CGRect(x: 35, y: 200, width: 250, height: 50)
segmentedControl.center = view.center
segmentedControl.tintColor = .blue
view.addSubview(segmentedControl)

// custom function
updateSegmentTextColor(segmentedControl)

// Add the selected index if you need AFTER the updates
segmentedControl.selectedSegmentIndex = 1
}

You get this

Custom UISegmentControl Title Label Color Swift iOS UIKit

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:

Sample Image

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:

Sample Image

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:

Sample Image

And is the result for background view white and segmented control with color:

Sample Image

Swift: Background color change in selected segment of UISegmentControl

The issue with the Swift code is the treatment of the optional:
(sender.subviews[i].isSelected) != nil will be true even if isSelected is false.

Try writing your loop using the Swift syntax

for subview in (sender.subviews as! [UIView]) {
if (subview.isSelected) {
subview.tintColor = UIColor.redColor()
}
else {
subview.tintColor = nil
}
}

At least in that loop you are actually testing whether or not the subview is selected instead of whether or not the view is not nil.

UISegmentedControl selected segment color

I found A Simple Way to Add Color for Selected Segment in UISegmentcontrol

sender is UISegmentControl

for (int i=0; i<[sender.subviews count]; i++) 
{
if ([[sender.subviews objectAtIndex:i]isSelected] )
{
UIColor *tintcolor=[UIColor colorWithRed:127.0/255.0 green:161.0/255.0 blue:183.0/255.0 alpha:1.0];
[[sender.subviews objectAtIndex:i] setTintColor:tintcolor];
}
else
{
[[sender.subviews objectAtIndex:i] setTintColor:nil];
}
}

Check its Working For Me



Related Topics



Leave a reply



Submit