Scenario
I have a peculiar bug in my subclassed UISegmentedControl. What I have simply done is subclassed a UISegmentedControl to remove the default indicators of selection/deselection and used a custom CALayer as an indicator for the same. At the same time, I have modified the titleTextAttributes to complement the UI.
Problem
When the view first appears and default selected index is 0, it looks like this:

When I try to change the selectedSegmentIndex to 1 it becomes:

Where it should look like this (corrected once you change the selectedSegmentIndex a few times):

This behaviour of titleTextAttributes not changing is random, however 2 cases when this happens 100% of the time are:
I have not found subclassing notes in the UISegmentedControl official docs.
Sample project HERE.
NOTE: If you use only 2 segments, you will never the see the title of the segment at index 1 on selection.
Indeed it's a weird behavior.
You can workaround it adding an explicit call to [self setNeedsLayout] after changing the indication layer frame.
//
// RBLSegmentedControl.m
// Rabbler
//
// Created by Utkarsh Singh on 05/11/15.
// Copyright © 2015 Neeraj SIngh. All rights reserved.
//
#import "NPSegmentedControl.h"
@interface NPSegmentedControl ()
@property (nonatomic, retain) CALayer* selectedIndicationLayer;
@end
@implementation NPSegmentedControl
- (instancetype)initWithItems:(NSArray *)items {
if (self = [super initWithItems:items]) {
self.selectedIndicationLayer.frame = CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width / items.count, self.frame.size.height);
[self addTarget:self action:@selector(segmentedControlDidChange) forControlEvents:UIControlEventValueChanged];
NSDictionary* selectedAttributes = @{NSFontAttributeName:[UIFont fontWithName:@"HelveticaNeue-Light" size:15],
NSForegroundColorAttributeName:[UIColor whiteColor]};
NSDictionary* deselectedAttributes = @{NSFontAttributeName:[UIFont fontWithName:@"HelveticaNeue-Light" size:15],
NSForegroundColorAttributeName:[UIColor redColor]};
NSDictionary* highlightedAttributes = @{NSFontAttributeName:[UIFont fontWithName:@"HelveticaNeue-Light" size:15],
NSForegroundColorAttributeName:[[UIColor redColor] colorWithAlphaComponent:0.6f]};
[self setTitleTextAttributes:deselectedAttributes forState:UIControlStateNormal];
[self setTitleTextAttributes:selectedAttributes forState:UIControlStateSelected];
[self setTitleTextAttributes:highlightedAttributes forState:UIControlStateHighlighted];
}
return self;
}
- (void) segmentedControlDidChange {
[self animateSegmentSelectionChange];
if (self.delegate && [self.delegate respondsToSelector:@selector(segmentedControlDidChangeSelectedSegment:)]) {
[self.delegate segmentedControlDidChangeSelectedSegment:self.selectedSegmentIndex];
}
}
- (void) animateSegmentSelectionChange {
[UIView animateWithDuration:0.25
delay:0
options:(UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionBeginFromCurrentState)
animations:^{
CGRect frame = self.selectedIndicationLayer.frame;
frame.origin.x = self.selectedSegmentIndex * [UIScreen mainScreen].bounds.size.width / self.numberOfSegments;
self.selectedIndicationLayer.frame = frame;
[self setNeedsLayout]; // <--
} completion:nil];
}
- (CALayer *) selectedIndicationLayer {
if (!_selectedIndicationLayer) {
_selectedIndicationLayer = [CALayer layer];
_selectedIndicationLayer.backgroundColor = [[UIColor redColor] CGColor];
_selectedIndicationLayer.cornerRadius = self.frame.size.height /2;
_selectedIndicationLayer.borderColor = [UIColor whiteColor].CGColor;
_selectedIndicationLayer.borderWidth = 1.5f;
[self.layer insertSublayer:_selectedIndicationLayer atIndex:0];
}
return _selectedIndicationLayer;
}
- (void) setSelectedSegmentIndex:(NSInteger)selectedSegmentIndex {
[super setSelectedSegmentIndex:selectedSegmentIndex];
[self animateSegmentSelectionChange];
}
- (void) setIndicatorColor:(UIColor *)indicatorColor {
self.selectedIndicationLayer.backgroundColor = indicatorColor.CGColor;
}
@end
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With