English Français

Le contexte

Un des usages de l'objet UISegmentedControl peut être celui d'une barre d'onglet pour naviguer entre des vues, ou bien celui d'un sélecteur entre différentes valeur. Dans le cas d'un UISegmentedControl utilisant le style UISegmentedControlStyleBar, le segment sélectionné est juste plus sombre que les segments non sélectionnés. Selon le choix de couleur du contrôle, cette distinction peut être assez difficile à faire (exemple ci-dessous).

Standard behavior for UISegmentedControl

Le but de ce billet est de montrer qu'avec un peu de code, il est tout à fait possible d'obtenir un comportement autre, avec une couleur pour le segment sélectionné tout à fait différente de celle des autres segments (exemple ci-dessous).

Better behavior for UISegmentedControl

Le code

Tout d'abord, vous trouverez en fin de ce billet une archive zip avec un projet XCode contenant le code utilisé pour ce billet. Pour la suite, il faudra tenir compte des éléments suivants :

  • L'objet UISegmentedControl doit être du style UISegmentedControlStyleBar (obligatoire).
  • Un selecteur sur « Value Changed » pointe sur la méthode « -(IBAction)selectSegment:(id)sender » (à adapter selon vos besoins).

Il faut ajouter à la classe dans laquelle vous manipulez l'objet UISegmentedControl une fonction permettant de trier des UIView en fonction de leur coordonnées horizontales :

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

Puis, dans la méthode « -(IBAction)selectSegment:(id)sender », ajoutez simplement le code suivant :

// 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];
    }