UISegmentedControl选定的段颜色


70

有什么方法可以自定义选定段的颜色UISegmentedControl

我找到了segmentedController.tintColor属性,该属性使我可以自定义整个分段控件的颜色。问题是,当我为tintColor属性选择鲜艳的颜色时,所选段几乎变得无法识别(其颜色与分段控件的其余部分几乎相同,因此很难区分所选段和未选中段)。因此,我无法使用任何良好的鲜艳颜色进行分段控制。解决方案是为选定的细分颜色提供一些单独的属性,但我找不到它。有人解决了吗?


从理论上讲,此组件旨在防止这种情况发生。如果您选择背景色和淡色,则它将交替显示选定的和取消选定的颜色。即,如果您选择背景黑色和白色色调,则选择一种时,它将带有白色背景和黑色色调,反之亦然。
jose920405 '16

Answers:


53

我在UISegmentcontrol中找到了一种为所选段添加颜色的简单方法

发件人是UISegmentControl

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

检查它为我工作


3
如果子视图响应选择器isSelected和setTintColor,则应添加完整性检查;否则,当Apple更改UISegmentedControl的工作方式时,代码将崩溃。
srgtuszy 2012年

在我看来,这可能会被拒绝。有人在App Store中尝试过此代码吗?
yonix 2012年

4
@yonix:虽然看起来很容易破解,但它不使用私有API。它应该是蛮好用的。
Tom Fobear 2012年

2
这是一个很好的解决方案,但我发现我还需要删除中断,并添加else [[sender.subviews objectAtIndex:i] setTintColor:sender.tintColor];以重置旧的色彩
elimirks 2013年

我已经在我的应用程序中尝试了上面的代码,但未被拒绝。我认为我的目标版本是ios 8。y不被拒绝
ShujatAli 2015年

74

这是将所选段更改为任何RGB颜色的绝对最简单的方法。无需子类化或黑客入侵。

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

此示例显示了重要步骤:

  1. 将控件样式设置为“ StyleBar”,这是工作所需的样式
  2. 首先将整个控件的未选择颜色设置为橙色
  3. 将所选线段的颜色设置为绿色

笔记:

  • 步骤1和2可以在界面生成器中完成,也可以如图所示在代码中完成。但是,步骤3只能用代码完成
  • 使用这样的符号“ 123.0 / 255.0”设置颜色值只是使RGB值突出而不是UIColor要求的标准化浮点值的一种方法(如果愿意,可以忽略它)

疯了的道具给你,为这个老问题贴出答案。我找到了它,您的回复极大地帮助了我!我已经实现了分段控件,所以我只需要使用最后一行。完美的工作,谢谢!
Stunner

9
@Lee Whitney,我认为所选细分的索引与segmentedcontrol的子视图的索引不同。
杰克

5
好吧,这太有意义了。我只是无法点击它。我在IB中创建了一个2段式UISegCont,选择了索引0,并将其色调分配为深灰色。然后,我使用最后一行定义所有选定线段的颜色。但是,当出现VC时,索引0段为黑色,索引1段为深灰色。然后,当我单击索引1细分时,索引0细分会以自定义颜色显示。??似乎每次UISegCiont状态更改时都需要定义颜色。
mputnamtennessee

4
那不行 将newTintColor设置为整个控件的tintColor是可行的,但是将newSelectedTintColor设置为第一个子视图的tintColor则不起作用。
亚历克西斯(Alexis)2013年

4
注:.segmentedControlStyle在的iOS 7.0弃用
泰伯

23

为此,您只需找到选定的段即可,例如,通过遍历分段控件的子视图并测试isSelected属性,然后只需setTintColor:在该子视图上调用方法即可。

我是通过将操作连接到Interface Builder中ValueChanged事件上的每个分段控件来实现的,我将它们连接到视图控制器文件中的此方法,这实质上是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]];
        }
    }
}

为了确保每次用户打开视图时控件都能正确显示,我还必须重写该-(void)viewDidAppear:animated方法并按如下方式调用该方法:

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

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

对于某些奖励积分,如果您确实希望将分段控件设置为在选择时使用白色色调,那么您还希望在选择文本时将其颜色更改为黑色,您可以这样做:

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

随着iOS 6的引入,无法在viewDidAppear方法中首次设置所选项目的色泽,为了解决此问题,我使用了集中式调度功能,在不到一秒钟的时间内更改了所选颜色,如下所示:

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

感谢您对iOS 6提出的宝贵意见。我为在iOS 6中停止工作的每个细分设置了颜色设置代码,您的建议解决了我的问题。
daveywc 2012年

是的,我注意到我的解决方案不适用于iOS6。谢谢!
Mike Sprague

1
在iOS 6中不推荐使用dispatch_get_current_queue()。请改用dispatch_get_main_queue()。
tadasz 2013年

谢谢@tasasz,当我注意到此内容并忘了一切时,我打算用此更新答案,现在更新。不建议仅在调试期间根据文档使用不建议使用dispatch_get_current_queue(),以及UI更改仅应在主线程上进行的事实!
大卫·汤普森

9

由于某些原因,Apple不允许您更改标准UISegmentedControls的颜色。

但是,有一种“合法的”方法可以将分段控件样式更改为UISegmentedControlStyleBar。这使它看起来有些不同,您可能不喜欢它,但是它确实允许颜色。

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

//更改条形和广告以查看然后释放分段控制器

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

希望这对您有所帮助,

塞布·卡德(Seb Kade)“我在这里为您提供帮助”


8

编辑:此解决方案在iOS 6上不起作用。请参阅下面的David Thompson的答案。

这个线程真的很旧,但是没有一个简单的答案适合我。

只要您还原未选择的分段控件的颜色,可接受的答案就起作用。这样的事情将在您的值更改功能中起作用:

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

谢谢,msprague!完美运作。
lifjoy 2012年

6

这是uihacker的CustomSegmentedControl的修改后的版本(请参见注释中的注释)。我的想法是,从使用selectedIndex到isSelected方法,我改变了查找应该更改tintColor的子视图的方式。因为我正在使用具有3个或更多段的自定义UISegmentedControl,其子视图顺序会随机更改(即使uihacker的“ hasSetSelectedIndexOnce”标志也无法解决此问题!)。该代码仍处于开发初期,请您自担风险。欢迎任何评论:)

另外,我还添加了对界面生成器的支持,并覆盖了setSelectedSegmentIndex,以便它也更新了颜色。请享用!

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

它的工作,但我对viewdidload方法有一个疑问,我的分段控件使用默认颜色。在对任何段索引执行操作之后,段更改了它们的颜色,但是我最初需要这样做,因为在第一次viewdidload调用时。怎么可能?
Anju 2012年

将此添加到您的已细分的子类中:-(void)drawRect:(CGRect)rect {[super drawRect:rect]; [self toggleHighlightColors]; }
Vassily 2012年

@Annie @Vassily的建议解决了吗?或者,您也可以尝试拨打- (void)setSelectedSegmentIndex:(NSInteger)selectedSegmentIndex您的电话viewDidLoad:)
Hlung 2012年

@DeZigny很高兴您喜欢:D
Hlung 2012年

6

我知道这是一个老问题,但是现在在xcode 11 +中,您可以设置选定的细分色度颜色 在此处输入图片说明

在代码中我们可以使用selectedSegmentTintColor。可用的iOS 13+


1
注意:如果您的项目最初是在Xcode 10或更早版本中创建的,则可能需要将Storyboard文件的“ Opens in”(位于File Inspector中)更新为Xcode 11,才能看到此功能。
内森·霍瑟尔顿

3

用这个:

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


2

为了澄清@jothikenpachi上面提供的答案,我们发现以下UISegmentController类别在iOS6中运行良好,并允许在段上使用任意的开/关配色方案。另外,如果在将来的OS版本中更改了私有方法isSelected / setTintColor:,它将优雅地失败。有关私有API调用等的警告

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

}

注意,将在UISegmentController的- (IBAction) segmentAction: (id)sender方法中调用此类别方法。

还要注意的是,在iOS6中,您似乎可能首先需要在管理UIViewController中调用此方法,- (void)viewDidAppear:(BOOL)animated这可能会导致动画闪烁。为了最大程度地减少这种情况,请尝试在IB中将“ offColor”设置为UISegmentController的tintColor。


2

我只是在iOS 7上遇到过此问题,它与iOS6的工作方式不同。

在iOS 7中,所选细分的标签颜色与UISegementControl背景相同。在iOS 7上更改它的唯一方法是设置UISegmentControl的背景颜色。

segmentControl.backgroundColor = customColor;

2

我用了它,它一步就改变了所有的颜色。

mySegmentedControl.tintColor = [UIColor redColor]

1

我发现我可以在子视图上使用具有与分段相同索引的标签,以便以任何顺序将分段正确着色。

// 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

在细分之间进行切换时,前两个解决方案对我不起作用。

我的解决方案是在视图控制器中处理段更改事件,然后每次更改段时都调用此方法:

+ (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

我想知道为什么没有人提到 UIAppearanceProxy

苹果文档::

https://developer.apple.com/documentation/uikit/uisegmentedcontrol#1653545

样例代码:

    private class func applyUISegmentControlAppearance(){
    let apperance = UISegmentedControl.appearance()

    // Set Navigation bar Title colour
    let unselAttrib = [NSForegroundColorAttributeName:UIColor.yellow,
                                        NSFontAttributeName: UIFont.systemFont(ofSize: 15)]

    let selAttrib = [NSForegroundColorAttributeName:UIColor.red,
                     NSFontAttributeName: UIFont.boldSystemFont(ofSize: 15)]


    apperance.setTitleTextAttributes(unselAttrib, for: .normal)
    apperance.setTitleTextAttributes(selAttrib, for: .selected)
}

通话邀请: 您可以调用该方法AppDelegate

application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]? = nil) -> Bool


0

为了执行您的操作,可能必须访问未记录的功能和黑客,这肯定会让苹果大怒,并可能导致应用程序被拒绝。

现在,解决方案在于另一个技巧,您可以使用两个按钮来代替它们,并在单击它们时互换它们的图像。保持按钮靠近并保持半段控制的图像,以产生段控制的错觉,这就是我所建议的一切。

希望这可以帮助。

谢谢,

马杜普


是的,谢谢,您猜想使用看起来像分段控件的UIButton是您要自定义颜色的唯一方法……
Mike

@迈克:我也这么认为。可能有人建议其他解决方案不是黑客,而是确实使用了已记录的api。
Madhup Singh Yadav'Feb 16'10

0

您可以标记每个段,然后将TintColor设置为Tag:

#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

我发现以上答案非常有帮助。我正在使用分段控件来设置旋钮的精度。我混合了上面的答案,并提出了以下建议:

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

}

希望这对其他人有所帮助。对我来说,一个关键是能够使用以下方法重置未选择的索引: setTintColor:nil];


0
- (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
Try this solution.    

在此处输入图片说明

在此处输入图片说明

        @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
为什么要硬编码?这一切都可以通过情节提要
OhadM,2016年

赞成挖掘子视图并在其中更改backgroundColor的基本思想。这是未记录的行为,但是为我提供了一个简单的解决方案来控制各个细分背景的颜色。(Objective-C:sender.subviews [0] .backgroundColor)
Jeff

0
- (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
[segmentedControl setSelectedSegmentTintColor:[UIColor darkGrayColor]];

//For iOS 13

2
请不要仅发布代码作为答案,而应提供解释,说明代码的作用以及如何解决问题。带有解释的答案通常质量较高,并且更有可能吸引投票。
Mark Rotteveel

-1

这个Swift 4代码对我有用

segmentedControl.setTitleTextAttributes([NSAttributedStringKey.foregroundColor: UIColor.red], for: .selected)

可以确定这会更改文本的字体颜色,而不是所选项目的背景颜色。
特拉维斯M.18年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.