How to change the colors of a segment in a UISegmentedControl in iOS 13?

前端 未结 14 740
醉话见心
醉话见心 2020-11-30 18:13

A UISegmentedControl has a new appearance in iOS 13 and existing code to alter the colors of the segmented control no longer work as they did.

Prior to

相关标签:
14条回答
  • 2020-11-30 18:35

    iOS13 UISegmentController

    how to use:

    segment.setOldLayout(tintColor: .green)
    
    extension UISegmentedControl
    {
        func setOldLayout(tintColor: UIColor)
        {
            if #available(iOS 13, *)
            {
                let bg = UIImage(color: .clear, size: CGSize(width: 1, height: 32))
                 let devider = UIImage(color: tintColor, size: CGSize(width: 1, height: 32))
    
                 //set background images
                 self.setBackgroundImage(bg, for: .normal, barMetrics: .default)
                 self.setBackgroundImage(devider, for: .selected, barMetrics: .default)
    
                 //set divider color
                 self.setDividerImage(devider, forLeftSegmentState: .normal, rightSegmentState: .normal, barMetrics: .default)
    
                 //set border
                 self.layer.borderWidth = 1
                 self.layer.borderColor = tintColor.cgColor
    
                 //set label color
                 self.setTitleTextAttributes([.foregroundColor: tintColor], for: .normal)
                 self.setTitleTextAttributes([.foregroundColor: UIColor.white], for: .selected)
            }
            else
            {
                self.tintColor = tintColor
            }
        }
    }
    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()!)!
        }
    }
    
    0 讨论(0)
  • 2020-11-30 18:37

    Swift version of @Ilahi Charfeddine answer:

    if #available(iOS 13.0, *) {
       segmentedControl.setTitleTextAttributes([.foregroundColor: UIColor.white], for: .selected)
       segmentedControl.selectedSegmentTintColor = UIColor.blue
    } else {
       segmentedControl.tintColor = UIColor.blue
    }
    
    0 讨论(0)
  • 2020-11-30 18:37
    if (@available(iOS 13.0, *)) {
    
        [self.segmentedControl setTitleTextAttributes:@{NSForegroundColorAttributeName: [UIColor whiteColor], NSFontAttributeName: [UIFont systemFontOfSize:13]} forState:UIControlStateSelected];
        [self.segmentedControl setSelectedSegmentTintColor:[UIColor blueColor]];
    
    } else {
    
    [self.segmentedControl setTintColor:[UIColor blueColor]];}
    
    0 讨论(0)
  • 2020-11-30 18:37

    If you want to set the background to clear you have to do this:

    if #available(iOS 13.0, *) {
      let image = UIImage()
      let size = CGSize(width: 1, height: segmentedControl.intrinsicContentSize.height)
      UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
      image.draw(in: CGRect(origin: .zero, size: size))
      let scaledImage = UIGraphicsGetImageFromCurrentImageContext()
      UIGraphicsEndImageContext()
      segmentedControl.setBackgroundImage(scaledImage, for: .normal, barMetrics: .default)
      segmentedControl.setDividerImage(scaledImage, forLeftSegmentState: .normal, rightSegmentState: .normal, barMetrics: .default)
    }
    
    0 讨论(0)
  • 2020-11-30 18:38

    XCODE 11.1 & iOS 13

    Based on @Jigar Darji 's answer but a safer implementation.

    We first create a failable convenience initialiser:

    extension UIImage {
    
    convenience init?(color: UIColor, size: CGSize) {
        UIGraphicsBeginImageContextWithOptions(size, false, 1)
        color.set()
        guard let ctx = UIGraphicsGetCurrentContext() else { return nil }
        ctx.fill(CGRect(origin: .zero, size: size))
        guard
            let image = UIGraphicsGetImageFromCurrentImageContext(),
            let imagePNGData = image.pngData()
            else { return nil }
        UIGraphicsEndImageContext()
    
        self.init(data: imagePNGData)
       }
    }
    

    Then we extend UISegmentedControl:

    extension UISegmentedControl {
    
    func fallBackToPreIOS13Layout(using tintColor: UIColor) {
        if #available(iOS 13, *) {
            let backGroundImage = UIImage(color: .clear, size: CGSize(width: 1, height: 32))
            let dividerImage = UIImage(color: tintColor, size: CGSize(width: 1, height: 32))
    
            setBackgroundImage(backGroundImage, for: .normal, barMetrics: .default)
            setBackgroundImage(dividerImage, for: .selected, barMetrics: .default)
    
            setDividerImage(dividerImage,
                            forLeftSegmentState: .normal,
                            rightSegmentState: .normal, barMetrics: .default)
    
            layer.borderWidth = 1
            layer.borderColor = tintColor.cgColor
    
            setTitleTextAttributes([.foregroundColor: tintColor], for: .normal)
            setTitleTextAttributes([.foregroundColor: UIColor.white], for: .selected)
        } else {
            self.tintColor = tintColor
        }
      }
    }
    
    0 讨论(0)
  • 2020-11-30 18:42

    I've tried the workaround and it works great for me. Here's the Objective-C version:

    @interface UISegmentedControl (Common)
    - (void)ensureiOS12Style;
    @end
    
    @implementation UISegmentedControl (Common)
    - (void)ensureiOS12Style {
        // UISegmentedControl has changed in iOS 13 and setting the tint
        // color now has no effect.
        if (@available(iOS 13, *)) {
            UIColor *tintColor = [self tintColor];
            UIImage *tintColorImage = [self imageWithColor:tintColor];
            // Must set the background image for normal to something (even clear) else the rest won't work
            [self setBackgroundImage:[self imageWithColor:self.backgroundColor ? self.backgroundColor : [UIColor clearColor]] forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
            [self setBackgroundImage:tintColorImage forState:UIControlStateSelected barMetrics:UIBarMetricsDefault];
            [self setBackgroundImage:[self imageWithColor:[tintColor colorWithAlphaComponent:0.2]] forState:UIControlStateHighlighted barMetrics:UIBarMetricsDefault];
            [self setBackgroundImage:tintColorImage forState:UIControlStateSelected|UIControlStateSelected barMetrics:UIBarMetricsDefault];
            [self setTitleTextAttributes:@{NSForegroundColorAttributeName: tintColor, NSFontAttributeName: [UIFont systemFontOfSize:13]} forState:UIControlStateNormal];
            [self setDividerImage:tintColorImage forLeftSegmentState:UIControlStateNormal rightSegmentState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
            self.layer.borderWidth = 1;
            self.layer.borderColor = [tintColor 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;
    }
    @end
    
    0 讨论(0)
提交回复
热议问题