ios 自定义 UISegmentedControl 的颜色

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1196679/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-30 16:13:04  来源:igfitidea点击:

Customizing the colors of a UISegmentedControl

iosobjective-cuisegmentedcontrol

提问by nicktmro

Does anybody know of a way to customize the appearance of the string based UISegmentedControl? I am trying to set the background color of the cell and the text color differently depending on the selected state of the item.

有人知道自定义基于字符串的 UISegmentedControl 外观的方法吗?我试图根据项目的选定状态不同地设置单元格的背景颜色和文本颜色。

Alternatively, do you know of a way to create UIImages on the fly in which to include custom strings? (e.g. create UUImage with white background, overlay text, add to segmented control).

或者,您是否知道一种动态创建 UIImages 以包含自定义字符串的方法?(例如创建带有白色背景的 UUImage,覆盖文本,添加到分段控件)。

I know that you can only have strings or images in the segmented control...

我知道分段控件中只能有字符串或图像...

采纳答案by Arclite

UISegmentedControl has a tintColor property -- this allows you to change what color the control is, but not the general "style" (the rounded, beveled shape):

UISegmentedControl 有一个 tintColor 属性——这允许您更改控件的颜色,但不能更改一般的“样式”(圆形、斜角形状):

segmentedControl.tintColor = [UIColor blueColor];

As for creating UIImages on the fly, you can create a CGContext, do whatever drawing you need to in that context (including strings), and then get a UIImage out of the context's CGImage:

至于动态创建 UIImages,您可以创建一个 CGContext,在该上下文中执行您需要的任何绘图(包括字符串),然后从上下文的 CGImage 中获取 UIImage:

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


Please note, that if you use code like UIView.appearance().tintColor = .myColor(or equiv. in ObjC), the effect most likely won't take place.

请注意,如果您使用类似UIView.appearance().tintColor = .myColor(或在 ObjC 中等效)的代码,则很可能不会发生这种效果。

回答by jxdwinter

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

segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar;

回答by Portland Runner

Most of the answers here don't answer the specific question of how to set a button color based on selected state which implies another color is desired for unselected state. I struggled with this for quite some time and wanted to share my solution for others to use.

这里的大多数答案都没有回答如何根据选定状态设置按钮颜色的具体问题,这意味着未选定状态需要另一种颜色。我为此苦苦挣扎了很长一段时间,并想分享我的解决方案供其他人使用。

My example uses a UISegmentedControlwith three segments. The unselected color for all three should be the same to give it a uniform look. The selected state for the first and last segment have unique colors.

我的示例使用UISegmentedControl带有三个段的 a。所有三个未选择的颜色应该相同,以使其外观统一。第一个和最后一个段的选定状态具有独特的颜色。

enter image description here

在此处输入图片说明

The issue is that the segmented control is not guaranteed to be in the same order so the colors will get mixed up as you select back and forth. Dan posted a solution that uses tags but unfortunately it's no longer guaranteed to work for iOS 6 and up.

问题是不能保证分段控件的顺序相同,因此当您来回选择时,颜色会混淆。Dan 发布了一个使用标签的解决方案,但不幸的是,它不再保证适用于 iOS 6 及更高版本。

Most of this code is taken from this post. I changed it slightly to have unique selected colors.

大部分代码取自这篇文章。我稍微改变了它以获得独特的选择颜色。

What makes it work is the sorting but take note of these 2 important lines for setting the selected color:

使它起作用的是排序,但请注意这两条用于设置所选颜色的重要行:

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


I placed the code in it's own method because I'm loading these segmented controls in a table view and need to run it upon loading (existing states from storage) and when a user changes a selection. Now I just need to call [Self updateSegmentColors];when something changes.

我将代码放在它自己的方法中,因为我正在表视图中加载这些分段控件,并且需要在加载(存储中的现有状态)和用户更改选择时运行它。现在我只需要[Self updateSegmentColors];在发生变化时调用。

回答by manuelonix maneloide

All you have to do is:

您所要做的就是:

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

回答by Colin

The best way I have found of doing something like this is setting different attributes for different UIControlStates on the segmented control.

我发现做这样的事情的最好方法是为分段控件上的不同 UIControlStates 设置不同的属性。

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

回答by david72

Here is a sample code that works with iOS9, but it is a hack, and might not work in later versions:

这是一个适用于 iOS9 的示例代码,但它是一个 hack,可能在以后的版本中不起作用:

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

回答by Shakeel Ahmed

Font Color swift 3 and swift 4 if you want to change

字体颜色 swift 3 和 swift 4 如果你想改变

For Unselected item

对于未选择的项目

 segcntrl.setTitleTextAttributes(titleTextAttributes, for: .normal)

For Selected item

对于所选项目

  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)

回答by vinny

As of iOS13, you would be no longer able to modify the tint color of the segment controller. Need to use selectedSegmentTintColor if the color has to be customised. self.yourSegmentControl.selectedSegmentTintColor = UIColor(red: 240.0/255.0, green: 183.0/255.0, blue: 0.0/255.0, alpha: 1.0)

从 iOS13 开始,您将无法再修改段控制器的色调颜色。如果必须自定义颜色,则需要使用 selectedSegmentTintColor。self.yourSegmentControl.selectedSegmentTintColor = UIColor(红色:240.0/255.0,绿色:183.0/255.0,蓝色:0.0/255.0,alpha:1.0)

回答by IMFletcher

I wanted to accomplish something similar - set the background color of the selected segment to one color while the 'outline' of the rest of the segments were a different color.

我想完成类似的事情 - 将所选段的背景颜色设置为一种颜色,而其余段的“轮廓”是不同的颜色。

Borrowing heavily from Portland Runner's answer, the idea is to subclass the UISegmentedControl, and override 2 methods to both style the initial state as well as capture the change event to style it automatically as the user selects different segments.

大量借用Portland Runner 的答案,想法是将 UISegmentedControl 子类化,并覆盖 2 个方法来设置初始状态的样式以及捕获更改事件以在用户选择不同的段时自动设置样式。

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

回答by okysabeni

I was able to do it via Interface Builder in XCode 6. Attached is the tint property:

我能够通过 XCode 6 中的 Interface Builder 做到这一点。附加的是 tint 属性:

enter image description here

在此处输入图片说明