iosswifttintcolor

UISegmentedControl TintColor to Gradient Color


I am trying to set UIsegmentedControl tint color for the selected segment to gradient color and I am unable to do it

I am trying to follow this article https://www.bethedev.com/2019/02/set-gradient-tint-color-for-segmented.html

Trying to use this code:

segmentedControl.setTitleTextAttributes([NSAttributedString.Key.foregroundColor:UIColor.white],for: UIControl.State.normal)
        segmentedControl.setTitleTextAttributes([NSAttributedString.Key.foregroundColor:UIColor.white],for: UIControl.State.selected)  

fileprivate func updateGradientBackground() {
        let sortedViews = segmentedControl.subviews.sorted( by: { $0.frame.origin.x < $1.frame.origin.x } )
        for (_, view) in sortedViews.enumerated() {
//            let gradientImage = gradient(size: segmentedControl.frame.size, color: [UIColor.cyan,UIColor.blue])!
            view.backgroundColor = UIColor(patternImage: UIImage(named: "segmentedRectangle.png")!)
            view.tintColor = UIColor.clear
        }
    }

I am expecting only one segment to be of the segmentedRectangle.png image color but it is displaying on the entire segmented control like this.


Solution

  • Try this code, I put comments on relevant parts. Let me know if you need more explanation.

     let segmentedControl: UISegmentedControl = {
           let view =  UISegmentedControl(items: ["Pounds", "Kilograms"])
            view.selectedSegmentIndex = 0
            view.tintColor = .black
            view.backgroundColor = .white
            view.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width - 40, height: 20)
            /// Gradient
            let gradient = CAGradientLayer()
            gradient.frame =  CGRect(x: 0, y: 0, width:  UIScreen.main.bounds.width - 40, height: 20)
            let leftColor = UIColor.red
            let rightColor = UIColor.purple
            gradient.colors = [leftColor.cgColor, rightColor.cgColor]
            gradient.startPoint = CGPoint(x: 0, y: 0.5)
            gradient.endPoint = CGPoint(x: 1.0, y: 0.5)
            /// Create gradient image
            UIGraphicsBeginImageContext(gradient.frame.size)
            gradient.render(in: UIGraphicsGetCurrentContext()!)
            let segmentedControlImage = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
    
            // Normal Image
            let rect: CGRect = CGRect(x: 0, y: 0, width: 1, height: 1)
            UIGraphicsBeginImageContext(rect.size);
            let context:CGContext = UIGraphicsGetCurrentContext()!;
            context.setFillColor(UIColor.white.cgColor)
            context.fill(rect)
            let normalImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
            UIGraphicsEndImageContext()
            /// Set segmentedControl image
            view.setBackgroundImage(normalImage, for: .normal, barMetrics: .default)
            view.setBackgroundImage(segmentedControlImage, for: .selected, barMetrics: .default)
            return view
        }()
    
    

    Usage: On your ViewDidLoad set navigationItem title view as your segmented control like so:-

    
    self.navigationItem.titleView = segmentedControl
    
    

    Output

    I think with few modifications/custominization you can get want you want, Cheers :)

    StoryBoard/InterfaceBuilder

    Just call this inside your ViewDidLoad and pass your outlet name on the function call: -

       func configureSegementedControl(segmentedControl: UISegmentedControl) {
            segmentedControl.selectedSegmentIndex = 0
            segmentedControl.tintColor = .black
            segmentedControl.backgroundColor = .white
            segmentedControl.frame = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width - 40, height: 20)
            /// Gradient
            let gradient = CAGradientLayer()
            gradient.frame =  CGRect(x: 0, y: 0, width:  UIScreen.main.bounds.width - 40, height: 20)
            let leftColor = UIColor.red
            let rightColor = UIColor.purple
            gradient.colors = [leftColor.cgColor, rightColor.cgColor]
            gradient.startPoint = CGPoint(x: 0, y: 0.5)
            gradient.endPoint = CGPoint(x: 1.0, y: 0.5)
            /// Create gradient image
            UIGraphicsBeginImageContext(gradient.frame.size)
            gradient.render(in: UIGraphicsGetCurrentContext()!)
            let segmentedControlImage = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            // Normal Image
            let rect: CGRect = CGRect(x: 0, y: 0, width: 1, height: 1)
            UIGraphicsBeginImageContext(rect.size);
            let context:CGContext = UIGraphicsGetCurrentContext()!;
            context.setFillColor(UIColor.white.cgColor)
            context.fill(rect)
            let normalImage:UIImage = UIGraphicsGetImageFromCurrentImageContext()!
            UIGraphicsEndImageContext()
            /// Set segmentedControl image
            segmentedControl.setBackgroundImage(normalImage, for: .normal, barMetrics: .default)
            segmentedControl.setBackgroundImage(segmentedControlImage, for: .selected, barMetrics: .default)
        }