English Français

The context

Object UISegmentedControl may be used to act as a tab bar in order to navigate between views, or to act a selector between many choices. In the case of a UISegmentedControl with UISegmentedControlStyleBar style, the selected segment is only darker than the unselected ones. Depending on the control's tint color, the distinction may be difficult to see (example below).

Standard behavior for UISegmentedControl

The goal of this post is to show that with a few code, it's possible to obtain an other behavior, with a selected segment differently colored than the others (example below)

Better behavior for UISegmentedControl

The code

First of all, you'll find at the end of this post a zip archive containing an XCode project with the code used for this post. From now until the end of this post, you'll have to keep the following elements in mind:

  • UISegmentedControl object must use UISegmentedControlStyleBar style (mandatory).
  • A selector on “Value Changed” points on the method “-(IBAction)selectSegment:(id)sender” (adapt to fit your needs).

You have to append to the class where you use UISegmentedControl object a function which sorts UIView by their horizontal coordinates:

NSInteger static compareViewsByOrigin(id sp1, id sp2, void *context)
{
    // UISegmentedControl segments use UISegment objects (private API). But we can safely cast them to UIView objects.
    float v1 = ((UIView *)sp1).frame.origin.x;
    float v2 = ((UIView *)sp2).frame.origin.x;
    if (v1 < v2)
        return NSOrderedAscending;
    else if (v1 > v2)
        return NSOrderedDescending;
    else
        return NSOrderedSame;
}

Then, append to “-(IBAction)selectSegment:(id)sender” method the following code:

// Get number of segments
    int numSegments = [betterSegmentedControl.subviews count];
 
    // Reset segment's color (non selected color)
    for( int i = 0; i < numSegments; i++ ) {
        // reset color
        [[betterSegmentedControl.subviews objectAtIndex:i] setTintColor:nil];
        [[betterSegmentedControl.subviews objectAtIndex:i] setTintColor:[UIColor colorWithRed:200/255.0 green:200/255.0 blue:200/255.0 alpha:1]];
    }
 
    // Sort segments from left to right
    NSArray *sortedViews = [betterSegmentedControl.subviews sortedArrayUsingFunction:compareViewsByOrigin context:NULL];
 
    // Change color of selected segment
    [[sortedViews objectAtIndex:betterSegmentedControl.selectedSegmentIndex] setTintColor:[UIColor colorWithRed:255/255.0 green:0/255.0 blue:0/255.0 alpha:1]];
 
    // Remove all original segments from the control
    for (id view in betterSegmentedControl.subviews) {
        [view removeFromSuperview];
    }
 
    // Append sorted and colored segments to the control
    for (id view in sortedViews) {
        [betterSegmentedControl addSubview:view];
    }

And that's all !