Search code examples
swiftuisegmentedcontroltextcolor

Customise font color of each segment in UISegmented Control


I'm, trying to configure segmented control bar.

The goal is to make text font of each segment in different colour. So it should look like this: example

I have read many topics, including this one: How to set UISegmentedControl Tint Color for individual segment But mainly it is discussed how to make tint colour different. And I try to make colours different in normal mode.


Solution

  • 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