How to Set the iOS13 Uisegmentedcontrol Backgroundcolor to White

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.

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

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

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()!)!
}
}

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

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.



Related Topics



Leave a reply



Submit