web-dev-qa-db-fra.com

Personnalisation des couleurs d'un UISegmentedControl

Quelqu'un connaît-il un moyen de personnaliser l'apparence de la chaîne UISegmentedControl? J'essaie de définir la couleur d'arrière-plan de la cellule et la couleur du texte différemment en fonction de l'état sélectionné de l'élément.

Alternativement, connaissez-vous un moyen de créer des UIImages à la volée pour inclure des chaînes personnalisées? (par exemple, créer UUImage avec un fond blanc, superposer du texte, ajouter au contrôle segmenté).

Je sais que vous ne pouvez avoir que des chaînes ou des images dans le contrôle segmenté ...

25
nicktmro

UISegmentedControl a une propriété tintColor - cela vous permet de changer la couleur du contrôle, mais pas le "style" général (la forme arrondie et biseautée):

segmentedControl.tintColor = [UIColor blueColor];

En ce qui concerne la création d'images UII à la volée, vous pouvez créer un CGContext, faire tout dessin dont vous avez besoin dans ce contexte (y compris les chaînes), puis extraire un UIImage de la CGImage du contexte:

CGContextRef drawContext = CGBitmapContextCreate(<many parameters>);
//do drawing here
CGImageRef finalImage = CGBitmapContextCreateImage(drawContext);
UIImage *cellImage = [UIImage finalImage];

Veuillez noter que si vous utilisez du code comme UIView.appearance().tintColor = .myColor (ou équivalent en ObjC), l'effet n'aura probablement pas lieu.

22
Arclite
segmentedControl.tintColor = [UIColor colorWithRed:0.61176f green:0.61176f  blue:0.61176f  alpha:1.0f];

segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar;
13
jxdwinter

La plupart des réponses ici ne répondent pas à la question spécifique de savoir comment définir une couleur de bouton en fonction de l'état sélectionné, ce qui implique qu'une autre couleur est souhaitée pour l'état non sélectionné. J'ai lutté avec cela pendant un certain temps et je voulais partager ma solution pour que d'autres l'utilisent.

Mon exemple utilise un UISegmentedControl avec trois segments. La couleur non sélectionnée pour les trois doit être la même pour lui donner un aspect uniforme. L'état sélectionné pour le premier et le dernier segment a des couleurs uniques.

enter image description here

Le problème est que le contrôle segmenté n'est pas garanti d'être dans le même ordre, donc les couleurs se mélangeront lorsque vous sélectionnerez d'avant en arrière. Dan a publié une solution qui utilise des balises mais malheureusement, il n'est plus garanti de fonctionner pour iOS 6 et plus.

La plupart de ce code est tiré de ce message . Je l'ai légèrement changé pour avoir des couleurs sélectionnées uniques.

Ce qui le fait fonctionner, c'est le tri, mais prenez note de ces 2 lignes importantes pour définir la couleur sélectionnée:

NSInteger selectedIdx = betterSegmentedControl.selectedSegmentIndex;
[[sortedViews objectAtIndex:selectedIdx] setTintColor:[self.segmentColors objectAtIndex:selectedIdx]];

- (void) updateSegmentColors
{
    UIColor *checkColor = [UIColor colorWithRed: 29/255.0 green:166/255.0 blue:47/255.0 alpha:1.0];
    NSArray *segmentColors = [[NSArray alloc] initWithObjects:checkColor, [UIColor blueColor], [UIColor redColor], nil];

    UISegmentedControl *betterSegmentedControl = self.StatusControl;

    // Get number of segments
    NSUInteger 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 blueColor]];
    }

    // Sort segments from left to right
    NSArray *sortedViews = [betterSegmentedControl.subviews sortedArrayUsingFunction:compareViewsByOrigin context:NULL];

    // Change color of selected segment
    NSInteger selectedIdx = betterSegmentedControl.selectedSegmentIndex;
    [[sortedViews objectAtIndex:selectedIdx] setTintColor:[self.segmentColors objectAtIndex:selectedIdx]];

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


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

J'ai placé le code dans sa propre méthode, car je charge ces contrôles segmentés dans une vue de table et je dois l'exécuter lors du chargement (états existants du stockage) et lorsqu'un utilisateur modifie une sélection. Maintenant, j'ai juste besoin d'appeler [Self updateSegmentColors]; quand quelque chose change.

11
Portland Runner

Tout ce que tu dois faire est:

// Get an array of the subviews of a UISegmentedControl, for example myUISegmentedControl:

NSArray *arri = [myUISegmentedControl subviews];

// Change the tintColor of each subview within the array:

[[arri objectAtIndex:0] setTintColor:[UIColor redColor]];

[[arri objectAtIndex:1] setTintColor:[UIColor greenColor]];
9

La meilleure façon que j'ai trouvée de faire quelque chose comme ça est de définir différents attributs pour différents UIControlStates sur le contrôle segmenté.

self.segmentedControl.tintColor = [UIColor cb_Grey1Color];
self.segmentedControl.backgroundColor = [UIColor cb_Grey3Color];
NSDictionary *selectedAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
                                    [UIFont cbGothamBookFontWithSize:13.0], NSFontAttributeName,
                                    [UIColor whiteColor], NSForegroundColorAttributeName,
                                    [UIColor cb_Grey1Color], NSBackgroundColorAttributeName, nil];
[self.segmentedControl setTitleTextAttributes:selectedAttributes forState:UIControlStateSelected];
NSDictionary *unselectedAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
                                      [UIFont cbGothamBookFontWithSize:13.0], NSFontAttributeName,
                                      [UIColor cb_Grey2Color], NSForegroundColorAttributeName,
                                      [UIColor cb_Grey3Color], NSBackgroundColorAttributeName, nil];
[self.segmentedControl setTitleTextAttributes:unselectedAttributes forState:UIControlStateNormal];
7
Colin

À partir d'iOS13, vous ne pourrez plus modifier la couleur de teinte du contrôleur de segment. Vous devez utiliser selectedSegmentTintColor si la couleur doit être personnalisée. self.yourSegmentControl.selectedSegmentTintColor = UIColor (rouge: 240.0/255.0, vert: 183.0/255.0, bleu: 0.0/255.0, alpha: 1.0)

2
vinny

Voici un exemple de code qui fonctionne avec iOS9, mais il s'agit d'un hack et peut ne pas fonctionner dans les versions ultérieures:

UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithItems:@[@"Title1", @"Title2"]];
for (id segment in [segmentedControl subviews])
{
    for (id view in [segment subviews])
    {
        NSString *desc = [view description];
        if ([desc containsString:@"UISegmentLabel"])
        {
            [segment setTintColor:([desc containsString:@"Title1"] ? [UIColor blueColor] : [UIColor greenColor])];
        }
    }
}
2
david72

Couleur de police Swift 3 et Swift 4 si vous souhaitez modifier

Pour l'élément non sélectionné

 segcntrl.setTitleTextAttributes(titleTextAttributes, for: .normal)

Pour l'élément sélectionné

  segcntrl.setTitleTextAttributes(titleTextAttributes, for: .selected)



//MARK:- Segment color change
    self.segc.setTitleTextAttributes([NSAttributedStringKey.foregroundColor: 
UIColor.white], for: UIControlState.selected)
    self.segc.setTitleTextAttributes([NSAttributedStringKey.foregroundColor: 
UIColor.white], for: UIControlState.normal)
2
Shakeel Ahmed

Je voulais accomplir quelque chose de similaire - définir la couleur d'arrière-plan du segment sélectionné sur une couleur tandis que le "contour" du reste des segments était d'une couleur différente.

Empruntant fortement à réponse de Portland Runner , l'idée est de sous-classer UISegmentedControl et de remplacer 2 méthodes pour à la fois styliser l'état initial et capturer l'événement de modification pour le styliser automatiquement lorsque l'utilisateur sélectionne différents segments.

- (void)layoutSubviews {
    [super layoutSubviews];
    [self updateSegmentColors];
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    [super touchesEnded:touches withEvent:event];
    [self updateSegmentColors];
}
- (void)updateSegmentColors {
    NSArray* segments = [self.subviews sortedArrayUsingComparator:^NSComparisonResult(id  _Nonnull obj1, id  _Nonnull obj2) {
        // UISegmentedControl segments use UISegment objects (private API). But we can safely cast them to UIView objects.
        float v1 = ((UIView *)obj1).frame.Origin.x;
        float v2 = ((UIView *)obj2).frame.Origin.x;
        if (v1 < v2) return NSOrderedAscending;
        else if (v1 > v2) return NSOrderedDescending;
        else return NSOrderedSame;
    }];
    for (int i=0; i<segments.count; i++) {
        if (i == self.selectedSegmentIndex) {
            [segments[i] setTintColor:[UIColor redColor]];
        } else {
            [segments[i] setTintColor:[UIColor grayColor]];
        }
    }
}
1
IMFletcher

J'ai pu le faire via Interface Builder dans XCode 6. Ci-joint la propriété de teinte:

enter image description here

1
okysabeni

Solution de storyboard

Xcode 11

Sélectionnez le contrôle et plusieurs options de couleurs sont maintenant disponibles. Si vous avez besoin d'un raffinement supplémentaire, consultez les attributs d'exécution définis par l'utilisateur.

image2

image1

0
Tommie C.