From d19d3882922ec1bd34f07400e709bfeacb671e0a Mon Sep 17 00:00:00 2001 From: Robert Moore Date: Fri, 27 Sep 2019 22:04:57 -0400 Subject: [PATCH] [BottomNavigation] Add support for custom badge and text colors. (#8518) Allows clients to set a custom badge background and text colors for all badges. On iOS 10+, the `UITabBarItem badgeColor` API allows customizing individual items' badge background colors as well. Setting the badge background and text color will allow clients using badges on Bottom Navigation to better-support Dark Mode. Closes #2833 --- .../src/MDCBottomNavigationBar.h | 11 ++++ .../src/MDCBottomNavigationBar.m | 28 +++++++++ .../src/private/MDCBottomNavigationItemView.h | 1 + .../src/private/MDCBottomNavigationItemView.m | 5 ++ .../MDCBottomNavigationBarSnapshotTests.m | 61 +++++++++++++++++++ .../unit/BottomNavigationItemViewTests.m | 12 ++++ .../tests/unit/MDCBottomNavigationBarTests.m | 3 + ...CustomBadgeColorsSetAfterItems_11_2@2x.png | 3 + ...ustomBadgeColorsSetBeforeItems_11_2@2x.png | 3 + ...oundAndUILabelDefaultTextColor_11_2@2x.png | 3 + 10 files changed, 130 insertions(+) create mode 100644 snapshot_test_goldens/goldens_64/MDCBottomNavigationBarSnapshotTests/testCustomBadgeColorsSetAfterItems_11_2@2x.png create mode 100644 snapshot_test_goldens/goldens_64/MDCBottomNavigationBarSnapshotTests/testCustomBadgeColorsSetBeforeItems_11_2@2x.png create mode 100644 snapshot_test_goldens/goldens_64/MDCBottomNavigationBarSnapshotTests/testNilBadgeColorsRendersClearBackgroundAndUILabelDefaultTextColor_11_2@2x.png diff --git a/components/BottomNavigation/src/MDCBottomNavigationBar.h b/components/BottomNavigation/src/MDCBottomNavigationBar.h index 6c556451d63..7ba2b71bb31 100644 --- a/components/BottomNavigation/src/MDCBottomNavigationBar.h +++ b/components/BottomNavigation/src/MDCBottomNavigationBar.h @@ -95,6 +95,17 @@ typedef NS_ENUM(NSInteger, MDCBottomNavigationBarAlignment) { */ @property(nonatomic, strong, nonnull) UIFont *itemTitleFont UI_APPEARANCE_SELECTOR; +/** + Background color for badges. Default is a red color. Only applies if the @c UITabBarItem + @c badgeColor is `nil`. + */ +@property(nonatomic, copy, nullable) UIColor *itemBadgeBackgroundColor; + +/** + Text color for badges. Default is white. + */ +@property(nonatomic, copy, nullable) UIColor *itemBadgeTextColor; + /** Color of selected item. Applies color to items' icons and text. If set also sets selectedItemTitleColor. Default color is black. diff --git a/components/BottomNavigation/src/MDCBottomNavigationBar.m b/components/BottomNavigation/src/MDCBottomNavigationBar.m index 20c4c25c590..0f5f1f8f3f8 100644 --- a/components/BottomNavigation/src/MDCBottomNavigationBar.m +++ b/components/BottomNavigation/src/MDCBottomNavigationBar.m @@ -19,6 +19,7 @@ #import #import "MaterialMath.h" +#import "MaterialPalettes.h" #import "MaterialShadowElevations.h" #import "MaterialShadowLayer.h" #import "MaterialTypography.h" @@ -100,6 +101,9 @@ - (void)commonMDCBottomNavigationBarInit { _sizeThatFitsIncludesSafeArea = NO; _titlesNumberOfLines = 1; _mdc_overrideBaseElevation = -1; + _itemBadgeTextColor = UIColor.whiteColor; + _itemBadgeBackgroundColor = MDCPalette.redPalette.tint700; + ; // Remove any unarchived subviews and reconfigure the view hierarchy if (self.subviews.count) { @@ -535,6 +539,8 @@ - (void)setItems:(NSArray *)items { itemView.contentHorizontalMargin = self.itemsContentHorizontalMargin; itemView.truncatesTitle = self.truncatesLongTitles; itemView.titlePositionAdjustment = item.titlePositionAdjustment; + itemView.badgeColor = self.itemBadgeBackgroundColor; + itemView.badgeTextColor = self.itemBadgeTextColor; MDCInkTouchController *controller = [[MDCInkTouchController alloc] initWithView:itemView]; controller.delegate = self; [self.inkControllers addObject:controller]; @@ -703,6 +709,28 @@ - (UIColor *)backgroundColor { return self.barView.backgroundColor; } +- (void)setItemBadgeTextColor:(UIColor *)itemBadgeTextColor { + _itemBadgeTextColor = itemBadgeTextColor; + for (MDCBottomNavigationItemView *itemView in self.itemViews) { + itemView.badgeTextColor = itemBadgeTextColor; + } +} + +- (void)setItemBadgeBackgroundColor:(UIColor *)itemBadgeBackgroundColor { + _itemBadgeBackgroundColor = itemBadgeBackgroundColor; + for (NSUInteger i = 0; i < self.items.count; ++i) { + UITabBarItem *item = self.items[i]; + if (@available(iOS 10.0, *)) { + // Skip items with a custom color + if (item.badgeColor) { + continue; + } + } + MDCBottomNavigationItemView *itemView = self.itemViews[i]; + itemView.badgeColor = itemBadgeBackgroundColor; + } +} + - (void)setBackgroundBlurEffectStyle:(UIBlurEffectStyle)backgroundBlurEffectStyle { if (_backgroundBlurEffectStyle == backgroundBlurEffectStyle) { return; diff --git a/components/BottomNavigation/src/private/MDCBottomNavigationItemView.h b/components/BottomNavigation/src/private/MDCBottomNavigationItemView.h index 648ec923bc8..0aad07d264c 100644 --- a/components/BottomNavigation/src/private/MDCBottomNavigationItemView.h +++ b/components/BottomNavigation/src/private/MDCBottomNavigationItemView.h @@ -45,6 +45,7 @@ @property(nonatomic, strong, nullable) UIImage *selectedImage; @property(nonatomic, strong, nullable) UIColor *badgeColor UI_APPEARANCE_SELECTOR; +@property(nonatomic, copy, nullable) UIColor *badgeTextColor; @property(nonatomic, strong, nullable) UIColor *selectedItemTintColor UI_APPEARANCE_SELECTOR; @property(nonatomic, strong, nullable) UIColor *unselectedItemTintColor UI_APPEARANCE_SELECTOR; @property(nonatomic, strong, nullable) UIColor *selectedItemTitleColor; diff --git a/components/BottomNavigation/src/private/MDCBottomNavigationItemView.m b/components/BottomNavigation/src/private/MDCBottomNavigationItemView.m index 518268fd6d9..0f9666561bc 100644 --- a/components/BottomNavigation/src/private/MDCBottomNavigationItemView.m +++ b/components/BottomNavigation/src/private/MDCBottomNavigationItemView.m @@ -511,6 +511,11 @@ - (void)setBadgeColor:(UIColor *)badgeColor { self.badge.badgeColor = badgeColor; } +- (void)setBadgeTextColor:(UIColor *)badgeTextColor { + _badgeTextColor = badgeTextColor; + self.badge.badgeValueLabel.textColor = badgeTextColor; +} + - (void)setBadgeValue:(NSString *)badgeValue { // Due to KVO, badgeValue may be of type NSNull. if ([badgeValue isKindOfClass:[NSNull class]]) { diff --git a/components/BottomNavigation/tests/snapshot/MDCBottomNavigationBarSnapshotTests.m b/components/BottomNavigation/tests/snapshot/MDCBottomNavigationBarSnapshotTests.m index 6019578c8fb..001eaee0fd6 100644 --- a/components/BottomNavigation/tests/snapshot/MDCBottomNavigationBarSnapshotTests.m +++ b/components/BottomNavigation/tests/snapshot/MDCBottomNavigationBarSnapshotTests.m @@ -445,4 +445,65 @@ - (void)testShadowColorRespondsToDynamicColor { #endif } +#pragma mark - Badging + +- (void)testCustomBadgeColorsSetAfterItems { + // Given + self.tabItem1.badgeValue = @""; + self.tabItem2.badgeValue = @"Gray on Yellow"; + self.tabItem3.badgeValue = @"Gray on Green"; + self.navigationBar.frame = CGRectMake(0, 0, MDCBottomNavigationBarTestWidthiPad, + MDCBottomNavigationBarTestHeightTypical); + + // When + if (@available(iOS 10.0, *)) { + self.tabItem3.badgeColor = UIColor.greenColor; + } + self.navigationBar.itemBadgeBackgroundColor = UIColor.yellowColor; + self.navigationBar.itemBadgeTextColor = UIColor.darkGrayColor; + + // Then + [self generateAndVerifySnapshot]; +} + +- (void)testCustomBadgeColorsSetBeforeItems { + // Given + self.tabItem1.badgeValue = @""; + self.tabItem2.badgeValue = @"Gray on Yellow"; + self.tabItem3.badgeValue = @"Gray on Green"; + self.navigationBar.frame = CGRectMake(0, 0, MDCBottomNavigationBarTestWidthiPad, + MDCBottomNavigationBarTestHeightTypical); + + // When + if (@available(iOS 10.0, *)) { + self.tabItem3.badgeColor = UIColor.greenColor; + } + self.navigationBar.itemBadgeBackgroundColor = UIColor.yellowColor; + self.navigationBar.itemBadgeTextColor = UIColor.darkGrayColor; + self.navigationBar.items = + @[ self.tabItem1, self.tabItem2, self.tabItem3, self.tabItem4, self.tabItem5 ]; + + // Then + [self generateAndVerifySnapshot]; +} + +- (void)testNilBadgeColorsRendersClearBackgroundAndUILabelDefaultTextColor { + // Given + self.tabItem1.badgeValue = @""; + self.tabItem2.badgeValue = @"Black on Clear"; + self.tabItem3.badgeValue = @"Black on Green"; + self.navigationBar.frame = CGRectMake(0, 0, MDCBottomNavigationBarTestWidthiPad, + MDCBottomNavigationBarTestHeightTypical); + + // When + if (@available(iOS 10.0, *)) { + self.tabItem3.badgeColor = UIColor.greenColor; + } + self.navigationBar.itemBadgeBackgroundColor = nil; + self.navigationBar.itemBadgeTextColor = nil; + + // Then + [self generateAndVerifySnapshot]; +} + @end diff --git a/components/BottomNavigation/tests/unit/BottomNavigationItemViewTests.m b/components/BottomNavigation/tests/unit/BottomNavigationItemViewTests.m index bc2260010b1..edb8717a071 100644 --- a/components/BottomNavigation/tests/unit/BottomNavigationItemViewTests.m +++ b/components/BottomNavigation/tests/unit/BottomNavigationItemViewTests.m @@ -104,6 +104,18 @@ - (void)testSetSelectedItemTintColorUpdatesInkColor { XCTAssertEqualObjects(item1.inkView.inkColor, item2.inkView.inkColor); } +- (void)testBadgeTextColorSetsBadgeLabelTextColor { + // Given + MDCBottomNavigationItemView *itemView = [[MDCBottomNavigationItemView alloc] init]; + itemView.badgeValue = @"123"; + + // When + itemView.badgeTextColor = UIColor.purpleColor; + + // Then + XCTAssertEqualObjects(itemView.badge.badgeValueLabel.textColor, UIColor.purpleColor); +} + - (void)testSetTitleVisibilityUpdatesLayout { // Given MDCBottomNavigationItemView *view = [[MDCBottomNavigationItemView alloc] init]; diff --git a/components/BottomNavigation/tests/unit/MDCBottomNavigationBarTests.m b/components/BottomNavigation/tests/unit/MDCBottomNavigationBarTests.m index 099ce050355..1bfc3dcede3 100644 --- a/components/BottomNavigation/tests/unit/MDCBottomNavigationBarTests.m +++ b/components/BottomNavigation/tests/unit/MDCBottomNavigationBarTests.m @@ -17,6 +17,7 @@ #import "../../src/private/MDCBottomNavigationBar+Private.h" #import "../../src/private/MDCBottomNavigationItemView.h" #import "MaterialBottomNavigation.h" +#import "MaterialPalettes.h" #import "MaterialShadowElevations.h" /** @@ -71,6 +72,8 @@ - (void)testDefaultValues { 0.001); XCTAssertLessThan(self.bottomNavBar.mdc_overrideBaseElevation, 0); XCTAssertNil(self.bottomNavBar.mdc_elevationDidChangeBlock); + XCTAssertEqualObjects(self.bottomNavBar.itemBadgeTextColor, UIColor.whiteColor); + XCTAssertEqualObjects(self.bottomNavBar.itemBadgeBackgroundColor, MDCPalette.redPalette.tint700); } #pragma mark - Fonts diff --git a/snapshot_test_goldens/goldens_64/MDCBottomNavigationBarSnapshotTests/testCustomBadgeColorsSetAfterItems_11_2@2x.png b/snapshot_test_goldens/goldens_64/MDCBottomNavigationBarSnapshotTests/testCustomBadgeColorsSetAfterItems_11_2@2x.png new file mode 100644 index 00000000000..f7972327d01 --- /dev/null +++ b/snapshot_test_goldens/goldens_64/MDCBottomNavigationBarSnapshotTests/testCustomBadgeColorsSetAfterItems_11_2@2x.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:aacf185ee92de1220c3cdafca6ccc251c1b1c761ca2f6e8ab172270761e549a1 +size 22953 diff --git a/snapshot_test_goldens/goldens_64/MDCBottomNavigationBarSnapshotTests/testCustomBadgeColorsSetBeforeItems_11_2@2x.png b/snapshot_test_goldens/goldens_64/MDCBottomNavigationBarSnapshotTests/testCustomBadgeColorsSetBeforeItems_11_2@2x.png new file mode 100644 index 00000000000..f7972327d01 --- /dev/null +++ b/snapshot_test_goldens/goldens_64/MDCBottomNavigationBarSnapshotTests/testCustomBadgeColorsSetBeforeItems_11_2@2x.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:aacf185ee92de1220c3cdafca6ccc251c1b1c761ca2f6e8ab172270761e549a1 +size 22953 diff --git a/snapshot_test_goldens/goldens_64/MDCBottomNavigationBarSnapshotTests/testNilBadgeColorsRendersClearBackgroundAndUILabelDefaultTextColor_11_2@2x.png b/snapshot_test_goldens/goldens_64/MDCBottomNavigationBarSnapshotTests/testNilBadgeColorsRendersClearBackgroundAndUILabelDefaultTextColor_11_2@2x.png new file mode 100644 index 00000000000..72ccfb1b455 --- /dev/null +++ b/snapshot_test_goldens/goldens_64/MDCBottomNavigationBarSnapshotTests/testNilBadgeColorsRendersClearBackgroundAndUILabelDefaultTextColor_11_2@2x.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:570d48e47a9e22c155e637652f803dbbf30bfe90fd9a74e6ff89378c6b92be35 +size 21629