Customizing the colors of a UISegmentedControl
UISegmentedControl has a tintColor property -- this allows you to change what color the control is, but not the general "style" (the rounded, beveled shape):
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:
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.
segmentedControl.tintColor = [UIColor colorWithRed:0.61176f green:0.61176f blue:0.61176f alpha:1.0f];
segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar;
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]];
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 UISegmentedControl
with 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.
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.
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.