web-dev-qa-db-fra.com

Couleur de segment sélectionnée par UISegmentedControl

Existe-t-il un moyen de personnaliser la couleur du segment sélectionné dans UISegmentedControl?

J'ai trouvé la propriété segmentedController.tintColor qui me permet de personnaliser la couleur de l'ensemble du contrôle segmenté. Le problème est que, lorsque je sélectionne une couleur vive pour la propriété tintColor, le segment sélectionné devient presque méconnaissable (sa couleur est presque identique à celle du reste du contrôle segmenté, de sorte qu'il est difficile de distinguer les segments sélectionnés et non sélectionnés). Je ne peux donc pas utiliser de bonnes couleurs vives pour un contrôle segmenté. La solution serait une propriété distincte pour la couleur de segment sélectionnée, mais je ne la trouve pas. Quelqu'un at-il résolu ce problème?

67
Mike

J'ai trouvé un moyen simple d'ajouter de la couleur pour le segment sélectionné dans UISegmentedcontrol

l'expéditeur est UISegmentedControl

for (int i=0; i<[sender.subviews count]; i++) 
{
    if ([[sender.subviews objectAtIndex:i]isSelected] ) 
    {               
    UIColor *tintcolor=[UIColor colorWithRed:127.0/255.0 green:161.0/255.0 blue:183.0/255.0 alpha:1.0];
    [[sender.subviews objectAtIndex:i] setTintColor:tintcolor];
    }
   else 
    {
        [[sender.subviews objectAtIndex:i] setTintColor:nil];
    }
}

Vérifiez son travail pour moi

53
jothikenpachi

Voici le moyen le plus simple et absolu de changer le segment sélectionné en n’importe quelle couleur RVB. Aucun sous-classement ou hacks requis.

segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar;

UIColor *newTintColor = [UIColor colorWithRed: 251/255.0 green:175/255.0 blue:93/255.0 alpha:1.0];
    segmentedControl.tintColor = newTintColor;

UIColor *newSelectedTintColor = [UIColor colorWithRed: 0/255.0 green:175/255.0 blue:0/255.0 alpha:1.0];
[[[segmentedControl subviews] objectAtIndex:0] setTintColor:newSelectedTintColor];

Cet exemple montre les étapes importantes:

  1. Définit le style de contrôle sur "StyleBar", ce qui est requis pour cela.
  2. Définit d'abord la couleur orange du contrôle entier
  3. Définit la couleur du segment Sélectionné sur vert

Remarques:

  • Les étapes 1 et 2 peuvent être effectuées dans le générateur d'interface .__ ou dans le code suivant. Cependant, l'étape 3 ne peut être effectuée que en code
  • Les valeurs de couleur définies avec la notation .__, comme celle-ci "123.0/255.0", sont Un moyen de faire en sorte que les valeurs RVB. ignorez-le si vous aimez)
74
whitneyland

Pour ce faire, il vous suffit de rechercher le segment sélectionné, par exemple en itérant sur les sous-vues du contrôle segmenté et en testant la propriété isSelected, puis d'appeler simplement la méthode setTintColor: sur cette sous-vue.

Je l'ai fait en connectant une action à chaque contrôle segmenté de l'événement ValueChanged dans Interface Builder. Je les ai connectés à cette méthode dans le fichier du contrôleur de vue, qui est essentiellement la réponse de msprague :

- (IBAction)segmentedControlValueChanged:(UISegmentedControl*)sender
{
    for (int i=0; i<[sender.subviews count]; i++)
    {
        if ([[sender.subviews objectAtIndex:i] respondsToSelector:@selector(isSelected)] && [[sender.subviews objectAtIndex:i]isSelected])
        {
            [[sender.subviews objectAtIndex:i] setTintColor:[UIColor whiteColor]];
        }
        if ([[sender.subviews objectAtIndex:i] respondsToSelector:@selector(isSelected)] && ![[sender.subviews objectAtIndex:i] isSelected])
        {
            [[sender.subviews objectAtIndex:i] setTintColor:[UIColor blackColor]];
        }
    }
}

Pour que le contrôle soit correctement affiché à chaque ouverture de la vue par l'utilisateur, je devais également remplacer la méthode -(void)viewDidAppear:animated et appeler la méthode comme suit:

-(void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];

    //Ensure the segmented controls are properly highlighted
    [self segmentedControlValueChanged:segmentedControlOne];
    [self segmentedControlValueChanged:segmentedControlTwo];
}

Pour certains points bonus, si vous souhaitez que le contrôle segmenté utilise une couleur de teinte blanche lors de la sélection, vous souhaitez également modifier la couleur du texte en noir lorsqu'il est sélectionné. Vous pouvez le faire comme suit:

//Create a dictionary to hold the new text attributes
NSMutableDictionary * textAttributes = [[NSMutableDictionary alloc] init];
//Add an entry to set the text to black
[textAttributes setObject:[UIColor blackColor] forKey:UITextAttributeTextColor];
//Set the attributes on the desired control but only for the selected state
[segmentedControlOne setTitleTextAttributes:textAttributes forState:UIControlStateSelected];

Avec l'introduction de iOS 6 , le réglage de la couleur de teinte de l'élément sélectionné pour la première fois dans la méthode viewDidAppear ne fonctionne pas. alors:

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.05 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{
        [self segmentedControlValueChanged:segmentedControlOne];
    });
22
David Thompson

Pour une raison quelconque, Apple ne vous autorise pas à modifier la couleur des contrôles UISegmentedControls standard. 

Il existe toutefois un moyen "légal" de changer le style de contrôle segmenté en UISegmentedControlStyleBar. Cela donne un aspect légèrement différent qui ne vous plaira peut-être pas, mais qui autorise les couleurs.

    NSArray *itemArray = [NSArray arrayWithObjects: @"One", @"Two", @"Three", nil];
UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithItems:itemArray];

// Modifier le style de barre et l'annonce pour afficher puis libérer le contrôleur segmenté

segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar;
segmentedControl.tintColor = [UIColor colorWithRed:.9 green:.1 blue:.1 alpha:1]; 
[self.view addSubview:segmentedControl];
[segmentedControl release];

J'espère que cela a aidé,

Seb Kade .__ "Je suis là pour vous aider"

9
Seb Kade

Edit : Cette solution ne fonctionne pas sur iOS 6. Voir la réponse de David Thompson ci-dessous.

Ce fil est vraiment vieux, mais aucune des réponses simples n'a fonctionné correctement pour moi.

La réponse acceptée fonctionne tant que vous inversez la couleur des contrôles segmentés désélectionnés . Quelque chose comme cela fonctionnera dans votre fonction de modification de la valeur:

for (int i=0; i<[control.subviews count]; i++) 
{
    if ([[control.subviews objectAtIndex:i]isSelected] ) 
    {               
        UIColor *tintcolor=[UIColor colorWithRed:127.0/255.0 green:161.0/255.0 blue:183.0/255.0 alpha:1.0];
        [[control.subviews objectAtIndex:i] setTintColor:tintcolor];
    } else {
        UIColor *tintcolor=[UIColor grayColor]; // default color
        [[control.subviews objectAtIndex:i] setTintColor:tintcolor];
    }
}
8
Mike Sprague

Voici ma version modifiée de CustomSegmentedControl de uihacker (voir crédit dans le commentaire). L'idée est de changer le moyen de trouver la sous-vue sur laquelle la teinte doit être modifiée, en passant de selectedIndex à la méthode isSelected. Parce que je travaillais avec un UISegmentedControl personnalisé qui comporte 3 segments ou plus et que l'ordre de sous-vue modifie de manière aléatoire (même l'indicateur "hasSetSelectedIndexOnce" de uihacker ne résout pas cela!). Le code en est encore à ses débuts, utilisez-le à vos risques et périls. Tout commentaire est le bienvenu :)

En outre, j'ai ajouté un support au générateur d'interface et substitué setSelectedSegmentIndex afin qu'il mette également à jour la couleur. Prendre plaisir!

CustomSegmentedControl.h

//
//  CustomSegmentedControl.h
//
//  Created by Hlung on 11/22/54 BE.
//  Copyright (c) 2554 __MyCompanyName__. All rights reserved.
//
//  Credit: http://uihacker.blogspot.com/2010/05/iphone-uisegmentedcontrol-custom-colors.html

@interface CustomSegmentedControl : UISegmentedControl {
    UIColor *offColor,*onColor;
}
@property (nonatomic,retain) UIColor *offColor,*onColor;
-(id)initWithItems:(NSArray *)items offColor:(UIColor*)offcolor onColor:(UIColor*)oncolor;
@end

CustomSegmentedControl.m

#import "CustomSegmentedControl.h"

@interface CustomSegmentedControl (private)
-(void)setInitialMode;
-(void)toggleHighlightColors;
@end

@implementation CustomSegmentedControl

@synthesize offColor,onColor;

-(id)initWithItems:(NSArray *)items offColor:(UIColor*)offcolor onColor:(UIColor*)oncolor {
    if (self = [super initWithItems:items]) {
        // Initialization code
        self.offColor = offcolor;
        self.onColor = oncolor;
        [self setInitialMode];

        // default to 0, other values cause arbitrary highlighting bug
        [self setSelectedSegmentIndex:0];
    }
    return self;
}
- (void)awakeFromNib {
    // default colors
    self.offColor = [UIColor colorWithWhite:0.8 alpha:1];
    self.onColor = self.tintColor;
    [self setInitialMode];

    [self setSelectedSegmentIndex:0];
}

-(void)setInitialMode
{
    // set essential properties
    [self setBackgroundColor:[UIColor clearColor]];
    [self setSegmentedControlStyle:UISegmentedControlStyleBar];

    // loop through children and set initial tint
    for( int i = 0; i < [self.subviews count]; i++ )
    {
        [[self.subviews objectAtIndex:i] setTintColor:nil];
        [[self.subviews objectAtIndex:i] setTintColor:offColor];
    }

    // listen for updates, [self setSelectedSegmentIndex:0] triggers UIControlEventValueChanged in 5.0, 4.3 doesn't (facepalm), use  if( self.window ) to fix this
    [self addTarget:self action:@selector(toggleHighlightColors) forControlEvents:UIControlEventValueChanged];
}

// ---------------
// hlung's version
// ---------------
-(void)toggleHighlightColors
{
    // the subviews array order randomly changes all the time, change to check for "isSelected" instead
    for (id v in self.subviews) {
        if ([v isSelected]) [v setTintColor:onColor];
        else [v setTintColor:offColor];
    }
}
// override: update color when set selection
- (void)setSelectedSegmentIndex:(NSInteger)selectedSegmentIndex {
    [super setSelectedSegmentIndex:selectedSegmentIndex];
    [self toggleHighlightColors];
}
// ---------------
@end
6
Hlung

Pour clarifier la réponse fournie ci-dessus par @jothikenpachi, nous avons constaté que la catégorie UISegmentController suivante fonctionnait bien dans iOS6 et permettait un jeu de couleurs arbitraire sur les segments. De plus, il échouera normalement si les méthodes privées isSelected/setTintColor: sont modifiées dans les prochaines versions du système d'exploitation. Mises en garde concernant les appels d'API privés, etc.

@implementation UISegmentedControl(CustomTintExtension) {
-(void) updateCustomTintColorOn:(UIColor*)onColor Off:(UIColor*)offColor {
// Convenience function to rest the tint colors after selection, called upon change of selected index

SEL tint = @selector(setTintColor:);

for (UIView *view in [self subviews]) {
    // Loop through the views...
    if (view && ([view respondsToSelector:tint])) {
        [view performSelector:tint withObject:nil];
    }
    if (view && ([view respondsToSelector:tint])) {
        [view performSelector:tint withObject:offColor];
    }
}

// Checking if segment subview is selected...
SEL isSelected = @selector(isSelected);
for (UIView *view in [self subviews]) {
    if ([view respondsToSelector:isSelected] && [view performSelector:isSelected withObject:nil])
    {
        [view performSelector:tint withObject:onColor];
        break;
    }
}

}

Notez que cette méthode de catégorie serait appelée depuis la méthode - (IBAction) segmentAction: (id)sender de UISegmentController.

Notez également qu'avec iOS6, il semble que vous deviez peut-être appeler cette méthode initialement dans la fonction - (void)viewDidAppear:(BOOL)animated de l'UIViewController qui gouverne, ce qui peut entraîner une animation flash. Pour minimiser cela, essayez de définir "offColor" comme teinteColor de UISegmentController dans IB.

2
MoFlo

Vous ne savez pas si cela va être approuvé par l'app store, mais j'ai écrit une sous-classe à UISegmentedControl qui vous permet de définir une couleur personnalisée sélectionnée et non sélectionnée. Vérifiez les notes pour plus d'informations:

http://uihacker.blogspot.com/2010/05/iphone-uisegmentedcontrol-custom-colors.html

2
cacheflowe

Je viens de rencontrer ce problème sur iOS 7, qui fonctionne différemment de iOS6.

Dans iOS 7, la couleur de l'étiquette du segment sélectionné est la même que celle de l'arrière-plan UISegementControl. La seule façon de le changer sur iOS 7 consiste à définir la couleur d'arrière-plan de UISegmentControl.

segmentControl.backgroundColor = customColor;
2
Barlow Tucker

J'ai utilisé cela et cela a changé toutes les couleurs en une étape.

mySegmentedControl.tintColor = [UIColor redColor]
2
smDeveloper

Utilisez ceci:

[[UISegmentedControl appearance] setTitleTextAttributes:@{NSForegroundColorAttributeName : [UIColor colorWithRed:255.0/255 green:37.0/255 blue:99.0/255 alpha:1.0]} forState:UIControlStateSelected];
1
user3272090
Try this solution.    

 enter image description here

 enter image description here

        @IBAction func dashBoardSegmentValueChanged(sender: AnyObject) {
            switch dashBoardSegment.selectedSegmentIndex
            {
            case 0:     
                sender.subviews.last?.backgroundColor = UIColor.whiteColor()
                sender.subviews.first?.backgroundColor =  UIColor.clearColor()

                break;
            case 1:            
                sender.subviews.first?.backgroundColor =  UIColor.whiteColor()
                sender.subviews.last?.backgroundColor = UIColor.clearColor()
                break;
            default:
                break;
            }
        }

Note: Make sure you select one segment subview as initial selected for easiness. It works if you have two segment subviews.
1
A.G

Les deux solutions principales ne fonctionnaient pas pour moi lors du basculement entre les segments.

Ma solution consistait à gérer l'événement de changement de segment dans mon contrôleur de vue, puis à appeler cette méthode chaque fois que le segment est modifié:

+ (void)setSegmentedControl:(UISegmentedControl *)segmentedControl 
              selectedColor:(UIColor *)selectedColor 
            deselectedColor:(UIColor *)deselectedColor
{
    for (int i = 0; i < segmentedControl.subviews.count; i++) 
    {
        id subView = [segmentedControl.subviews objectAtIndex:i];

        if ([subView isSelected])
            [subView setTintColor:selectedColor];
        else
            [subView setTintColor:deselectedColor];
    }    
}
1
Brandon O'Rourke

J'ai trouvé que je pouvais utiliser des balises sur les sous-vues avec le même index que les segments, afin que les segments soient colorés correctement dans n'importe quel ordre.

// In viewWillAppear set up the segmented control 

// then for 3 segments:  
self.navigationItem.titleView = segmentedControl;
//Order of subviews can change randomly!, so Tag them with same index as segment
[[[segmentedControl subviews]objectAtIndex:0]setTag:0]; 
[[[segmentedControl subviews]objectAtIndex:1]setTag:1];
[[[segmentedControl subviews]objectAtIndex:2]setTag:2];


// color follows the selected segment
- (IBAction)mySelector:(id)sender {
selector = [sender selectedSegmentIndex]
  for (id seg in [segmentedControl subviews]) {
    for (id label in [seg subviews]) {
        if ([seg tag] == selector){
            [seg setTintColor:selectedColor];
        } else {
            [seg setTintColor:nonSelectedColor];
        }
    }
  }
}

// in viewDidAppear for returning to the view
[segmentedControl setSelectedSegmentIndex:selector];
for (id seg in [segmentedControl subviews]) {
    for (id label in [seg subviews]) {
        if ([seg tag] == selector){
            [seg setTintColor:selectedColor];
        } else {
            [seg setTintColor:nonSelectedColor];
        }
    }
}
1
RexMac66

Vous pouvez baliser chacun des segments, puis définir le TintColor pourTag:

#define kTagOffState 0
#define kTagOnState  2

#define UIColorFromRGB(rgbValue) [UIColor \
        colorWithRed:((float)((rgbValue & 0xFF0000) >> 16))/255.0 \
        green:((float)((rgbValue & 0xFF00) >> 8))/255.0 \
        blue:((float)(rgbValue & 0xFF))/255.0 alpha:1.0]

//usage     UIColor color = UIColorFromRGB(0xF7F7F7);

 UIColor onColor = UIColorFromRGB(0xF7F7F7);
 UIColor offColor = UIColorFromRGB(0x878787);

        [multiStateControl setTag:kTagOffState forSegmentAtIndex:0];
        [multiStateControl setTag:kTagOnState forSegmentAtIndex:1];
        [multiStateControl setTintColor:onColor forTag:kTagOnState];
        [multiStateControl setTintColor:offColor forTag:kTagOffState];  
0
scooter133
- (IBAction)segmentedControlValueChanged:(UISegmentedControl *)sender {
    for (int i = 0; i < sender.subviews.count; i++) {
        UIControl *component = [sender.subviews objectAtIndex:i];
        if ([component respondsToSelector:@selector(isSelected)]) {
            UIColor *selectedColor = [UIColor greenColor];
            UIColor *normalColor   = [UIColor blackColor];
            UIColor *tint = component.isSelected ? selectedColor : normalColor;
            [component setTintColor:tint];
        }
    }
}
0
Ted

Ce code Swift 4 fonctionne pour moi

segmentedControl.setTitleTextAttributes([NSAttributedStringKey.foregroundColor: UIColor.red], for: .selected)
0
ayalcinkaya
- (IBAction)segmentControlValueChanged:(UISegmentedControl *)sender
{
    if ([[sender.subviews firstObject] respondsToSelector:@selector(setTintColor:)]) {
        for (id segment in sender.subviews) {
            if ([segment respondsToSelector:@selector(isSelected)] && [segment isSelected]) {
                [segment setTintColor:[UIColor redColor]];
            } else {
                [segment setTintColor:[UIColor grayColor]];
            }
        }
    }
}
0
1mperial

Pour faire ce que vous faites, vous devrez peut-être accéder aux fonctionnalités non documentées et aux hacks, ce qui rendra certainement Apple furieux, ce qui peut entraîner le rejet de votre application.

Maintenant, la solution réside dans une autre astuce, qui consiste à utiliser deux boutons à la place et à échanger leurs images lorsque vous cliquez dessus. Gardez les boutons plus proches et les images de contrôle semi-segmenté pour donner l’illusion d’un contrôle segmenté et c’est tout ce que je peux vous suggérer.

J'espère que cela t'aides.

Merci,

Madhup

0
Madhup Singh Yadav

J'ai trouvé les réponses ci-dessus très utiles. J'utilise le contrôle segmenté pour définir la précision d'un bouton. J'ai pris un hybride des réponses ci-dessus et suis venu avec ceci:

-(void) viewDidLoad {

NSArray *segments = [NSArray arrayWithObjects:@"Course", @"Fine",nil];

[knob setPrecision:0.1]; // initial precision
// Set starting values

UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithItems:segments];

segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar;
segmentedControl.frame = CGRectMake(120, 680, 228, 30);
[segmentedControl addTarget:self action:@selector(precisionSelect:) forControlEvents:UIControlEventValueChanged];
segmentedControl.momentary = YES;

[self.view addSubview:segmentedControl];
}   

- (void)precisionSelect:(UISegmentedControl*)sender
{   
    UIColor *tintcolor = [UIColor darkGrayColor];   
    if (sender.selectedSegmentIndex == 0) {
        [[sender.subviews objectAtIndex:0] setTintColor:nil];
        [[sender.subviews objectAtIndex:1] setTintColor:tintcolor];
    [knob setPrecision:0.1]; // Coarse
    } else {
        [[sender.subviews objectAtIndex:0] setTintColor:tintcolor];
        [[sender.subviews objectAtIndex:1] setTintColor:nil];
    [knob setPrecision:0.05]; // Fine
    }

}

J'espère que cela aide les autres ... Une clé pour moi était de pouvoir réinitialiser l'index non sélectionné à l'aide de: setTintColor:nil];

0
David DelMonte