Skip to content

Commit

Permalink
[Tabs] Add titleColorForState: API. (#7712)
Browse files Browse the repository at this point in the history
Adds a new API to affect the items' title color for `.selected` and `.normal` states.

Part of #7657
  • Loading branch information
Robert Moore committed Jun 25, 2019
1 parent 41369ec commit af0fe79
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 1 deletion.
16 changes: 16 additions & 0 deletions components/Tabs/src/TabBarView/MDCTabBarView.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,20 @@ __attribute__((objc_subclassing_restricted)) @interface MDCTabBarView : UIScroll
/** The color of the Tab bar's background. */
@property(nullable, nonatomic, copy) UIColor *barTintColor;

/**
Sets the color of the bar items' title for the given control state. Supports
@c UIControlStateNormal and @c UIControlStateSelected.
If no value for a control state is set, the value for @c UIControlStateNormal is used. If no value
for @c UIControlStateNormal is set, then a default value is used.
*/
- (void)setTitleColor:(nullable UIColor *)titleColor forState:(UIControlState)state;

/**
Returns the color of the bar items' title for the given control state.
If no value for a control state is set, the value for @c UIControlStateNormal is returned.
*/
- (nullable UIColor *)titleColorForState:(UIControlState)state;

@end
43 changes: 42 additions & 1 deletion components/Tabs/src/TabBarView/MDCTabBarView.m
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@
@interface MDCTabBarView ()

/** The views representing the items of this tab bar. */
@property(nonatomic, strong) NSArray<UIView *> *itemViews;
@property(nonnull, nonatomic, strong) NSArray<UIView *> *itemViews;

/** The title colors for bar items. */
@property(nonnull, nonatomic, strong) NSMutableDictionary<NSNumber *, UIColor *> *stateToTitleColor;

@end

Expand All @@ -34,6 +37,7 @@ - (instancetype)init {
if (self) {
_items = @[];
_itemViews = @[];
_stateToTitleColor = [NSMutableDictionary dictionary];
}
return self;
}
Expand Down Expand Up @@ -67,6 +71,7 @@ - (void)setItems:(NSArray<UITabBarItem *> *)items {
// TODO(#7645): Remove this if autoresizing masks are used.
itemView.translatesAutoresizingMaskIntoConstraints = NO;
itemView.titleLabel.text = item.title;
itemView.titleLabel.textColor = [self titleColorForState:UIControlStateNormal];
itemView.iconImageView.image = item.image;
[itemViews addObject:itemView];
[self addSubview:itemView];
Expand Down Expand Up @@ -97,6 +102,42 @@ - (void)setSelectedItem:(UITabBarItem *)selectedItem {
}

_selectedItem = selectedItem;
[self updateTitleColorForAllViews];
}

- (void)updateTitleColorForAllViews {
for (UITabBarItem *item in self.items) {
NSUInteger indexOfItem = [self.items indexOfObject:item];
// This is a significant error, but defensive coding is preferred.
if (indexOfItem == NSNotFound || indexOfItem >= self.itemViews.count) {
NSAssert(NO, @"Unable to find associated item view for (%@)", item);
continue;
}
UIView *itemView = self.itemViews[indexOfItem];
// Skip custom views
if (![itemView isKindOfClass:[MDCTabBarViewItemView class]]) {
continue;
}
MDCTabBarViewItemView *tabBarViewItemView = (MDCTabBarViewItemView *)itemView;
if (item == self.selectedItem) {
tabBarViewItemView.titleLabel.textColor = [self titleColorForState:UIControlStateSelected];
} else {
tabBarViewItemView.titleLabel.textColor = [self titleColorForState:UIControlStateNormal];
}
}
}

- (void)setTitleColor:(UIColor *)titleColor forState:(UIControlState)state {
self.stateToTitleColor[@(state)] = titleColor;
[self updateTitleColorForAllViews];
}

- (UIColor *)titleColorForState:(UIControlState)state {
UIColor *titleColor = self.stateToTitleColor[@(state)];
if (!titleColor) {
titleColor = self.stateToTitleColor[@(UIControlStateNormal)];
}
return titleColor;
}

#pragma mark - UIView
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,74 @@ - (void)testItemsWithMixedTitlesAndImages {

#pragma mark - MDCTabBarView Properties

- (void)testSetTitleColorForExplicitItemStates {
// Given
self.tabBarView.bounds = CGRectMake(0, 0, 360, kExpectedHeightTitlesAndIcons);
UITabBarItem *item1 = [[UITabBarItem alloc] initWithTitle:@"One" image:self.typicalIcon1 tag:0];
UITabBarItem *item2 = [[UITabBarItem alloc] initWithTitle:@"Two" image:self.typicalIcon2 tag:2];
UITabBarItem *item3 = [[UITabBarItem alloc] initWithTitle:@"Three" image:self.typicalIcon3 tag:3];
self.tabBarView.items = @[ item1, item2, item3 ];
self.tabBarView.selectedItem = item2;

// When
[self.tabBarView setTitleColor:UIColor.brownColor forState:UIControlStateSelected];
[self.tabBarView setTitleColor:UIColor.purpleColor forState:UIControlStateNormal];

// Then
[self generateSnapshotAndVerifyForView:self.tabBarView];
}

- (void)testSetTitleColorForNormalStateAppliesToSelectedItem {
// Given
self.tabBarView.bounds = CGRectMake(0, 0, 360, kExpectedHeightTitlesAndIcons);
UITabBarItem *item1 = [[UITabBarItem alloc] initWithTitle:@"One" image:self.typicalIcon1 tag:0];
UITabBarItem *item2 = [[UITabBarItem alloc] initWithTitle:@"Two" image:self.typicalIcon2 tag:2];
UITabBarItem *item3 = [[UITabBarItem alloc] initWithTitle:@"Three" image:self.typicalIcon3 tag:3];
self.tabBarView.items = @[ item1, item2, item3 ];
self.tabBarView.selectedItem = item2;

// When
[self.tabBarView setTitleColor:UIColor.purpleColor forState:UIControlStateNormal];

// Then
[self generateSnapshotAndVerifyForView:self.tabBarView];
}

- (void)testSetTitleColorExplicitlyToNilRendersSomeDefault {
// Given
self.tabBarView.bounds = CGRectMake(0, 0, 360, kExpectedHeightTitlesAndIcons);
UITabBarItem *item1 = [[UITabBarItem alloc] initWithTitle:@"One" image:self.typicalIcon1 tag:0];
UITabBarItem *item2 = [[UITabBarItem alloc] initWithTitle:@"Two" image:self.typicalIcon2 tag:2];
UITabBarItem *item3 = [[UITabBarItem alloc] initWithTitle:@"Three" image:self.typicalIcon3 tag:3];
self.tabBarView.items = @[ item1, item2, item3 ];
self.tabBarView.selectedItem = item2;

// When
[self.tabBarView setTitleColor:nil forState:UIControlStateNormal];
[self.tabBarView setTitleColor:nil forState:UIControlStateSelected];

// Then
[self generateSnapshotAndVerifyForView:self.tabBarView];
}

- (void)testChangingSelectionUpdatesItemStyle {
// Given
self.tabBarView.bounds = CGRectMake(0, 0, 360, kExpectedHeightTitlesAndIcons);
UITabBarItem *item1 = [[UITabBarItem alloc] initWithTitle:@"One" image:self.typicalIcon1 tag:0];
UITabBarItem *item2 = [[UITabBarItem alloc] initWithTitle:@"Two" image:self.typicalIcon2 tag:2];
UITabBarItem *item3 = [[UITabBarItem alloc] initWithTitle:@"Three" image:self.typicalIcon3 tag:3];
self.tabBarView.items = @[ item1, item2, item3 ];
self.tabBarView.selectedItem = item2;
[self.tabBarView setTitleColor:UIColor.purpleColor forState:UIControlStateNormal];
[self.tabBarView setTitleColor:UIColor.brownColor forState:UIControlStateSelected];

// When
self.tabBarView.selectedItem = item3;

// Then
[self generateSnapshotAndVerifyForView:self.tabBarView];
}

- (void)testBarTintColor {
// When
self.tabBarView.barTintColor = UIColor.purpleColor;
Expand Down
55 changes: 55 additions & 0 deletions components/Tabs/tests/unit/TabBarView/MDCTabBarViewTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -163,4 +163,59 @@ - (void)testSettingBackgroundColorUpdatesBarTintColor {
XCTAssertEqual(self.tabBarView.barTintColor, self.tabBarView.backgroundColor);
}

- (void)testTitleColorForStateFallsBackToNormalState {
// Given
[self.tabBarView setTitleColor:nil forState:UIControlStateNormal];
[self.tabBarView setTitleColor:nil forState:UIControlStateSelected];

// When
[self.tabBarView setTitleColor:UIColor.purpleColor forState:UIControlStateNormal];

// Then
XCTAssertEqualObjects([self.tabBarView titleColorForState:UIControlStateSelected],
UIColor.purpleColor);
}

- (void)testTitleColorForStateReturnsExpectedValue {
// Given
[self.tabBarView setTitleColor:nil forState:UIControlStateNormal];
[self.tabBarView setTitleColor:nil forState:UIControlStateSelected];

// When
[self.tabBarView setTitleColor:UIColor.purpleColor forState:UIControlStateNormal];
[self.tabBarView setTitleColor:UIColor.orangeColor forState:UIControlStateSelected];

// Then
XCTAssertEqualObjects([self.tabBarView titleColorForState:UIControlStateNormal],
UIColor.purpleColor);
XCTAssertEqualObjects([self.tabBarView titleColorForState:UIControlStateSelected],
UIColor.orangeColor);
}

- (void)testTitleColorForStateSetToNilFallsBackToNormal {
// Given
[self.tabBarView setTitleColor:nil forState:UIControlStateNormal];
[self.tabBarView setTitleColor:UIColor.cyanColor forState:UIControlStateSelected];

// When
[self.tabBarView setTitleColor:UIColor.purpleColor forState:UIControlStateNormal];
[self.tabBarView setTitleColor:nil forState:UIControlStateSelected];

// Then
XCTAssertEqualObjects([self.tabBarView titleColorForState:UIControlStateNormal],
UIColor.purpleColor);
XCTAssertEqualObjects([self.tabBarView titleColorForState:UIControlStateSelected],
UIColor.purpleColor);
}

- (void)testTitleColorForStateWithNoValuesReturnsNil {
// When
[self.tabBarView setTitleColor:nil forState:UIControlStateNormal];
[self.tabBarView setTitleColor:nil forState:UIControlStateSelected];

// Then
XCTAssertNil([self.tabBarView titleColorForState:UIControlStateNormal]);
XCTAssertNil([self.tabBarView titleColorForState:UIControlStateSelected]);
}

@end
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit af0fe79

Please sign in to comment.