Skip to content

Commit

Permalink
[BottomNavigation] Add theming extension (#7691)
Browse files Browse the repository at this point in the history
Adds a theming extension to the bottom navigation component. This follows the guidelines outlined in the design doc.

Design doc: go/mdc-ios-theming-extensions.

Closes #7565
  • Loading branch information
codeman7 committed Jun 24, 2019
1 parent 325e269 commit f7ac1db
Show file tree
Hide file tree
Showing 13 changed files with 593 additions and 70 deletions.
22 changes: 22 additions & 0 deletions MaterialComponents.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,28 @@ Pod::Spec.new do |mdc|
extension.dependency "MaterialComponents/schemes/Typography"
end

mdc.subspec "BottomNavigation+Theming" do |extension|
extension.ios.deployment_target = '9.0'
extension.public_header_files = "components/#{extension.base_name.split('+')[0]}/src/#{extension.base_name.split('+')[1]}/*.h"
extension.source_files = [
"components/#{extension.base_name.split('+')[0]}/src/#{extension.base_name.split('+')[1]}/*.{h,m}",
"components/#{extension.base_name.split('+')[0]}/src/#{extension.base_name.split('+')[1]}/private/*.{h,m}"
]
extension.dependency "MaterialComponents/#{extension.base_name.split('+')[0]}"
extension.dependency "MaterialComponents/ShadowElevations"
extension.dependency "MaterialComponents/schemes/Color"
extension.dependency "MaterialComponents/schemes/Container"
extension.dependency "MaterialComponents/schemes/Typography"

extension.test_spec 'UnitTests' do |unit_tests|
unit_tests.source_files = [
"components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/*.{h,m,swift}",
"components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/supplemental/*.{h,m,swift}"
]
unit_tests.resources = "components/#{extension.base_name.split('+')[0]}/tests/unit/#{extension.base_name.split('+')[1]}/resources/*"
end
end

# BottomSheet

mdc.subspec "BottomSheet" do |component|
Expand Down

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions catalog/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ target "MDCCatalog" do
'AppBar+Theming/UnitTests',
'BottomAppBar/UnitTests',
'BottomNavigation/UnitTests',
'BottomNavigation+Theming/UnitTests',
'BottomSheet/UnitTests',
'ButtonBar/UnitTests',
'Buttons/UnitTests',
Expand Down
21 changes: 18 additions & 3 deletions components/BottomNavigation/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,17 @@ mdc_objc_library(
],
)

mdc_extension_objc_library(
name = "Theming",
deps = [
":BottomNavigation",
"//components/ShadowElevations",
"//components/schemes/Color",
"//components/schemes/Container",
"//components/schemes/Typography",
],
)

filegroup(
name = "BundleFiles",
srcs = glob([
Expand Down Expand Up @@ -162,8 +173,8 @@ swift_library(
"4.2",
],
deps = [
":BottomNavigationBeta",
":BottomNavigation",
":BottomNavigationBeta",
":ColorThemer",
":ObjcExamples",
":TypographyThemer",
Expand All @@ -180,6 +191,7 @@ mdc_objc_library(
[
"tests/unit/*.m",
"tests/unit/*.h",
"tests/unit/Theming/*.m",
],
exclude = ["tests/unit/MDCBottomNavigationBarControllerTests.m"],
),
Expand All @@ -191,8 +203,10 @@ mdc_objc_library(
deps = [
":BottomNavigation",
":ColorThemer",
":Theming",
":TypographyThemer",
":private",
"//components/Typography",
],
)

Expand All @@ -212,10 +226,10 @@ mdc_objc_library(

ios_unit_test(
name = "unit_tests_beta",
deps = [":unit_test_beta_sources"],
minimum_os_version = "9.0",
flaky = 1,
minimum_os_version = "9.0",
test_host = "//components/private/Snapshot/TestHost",
deps = [":unit_test_beta_sources"],
)

mdc_unit_test_suite(
Expand All @@ -230,6 +244,7 @@ mdc_snapshot_objc_library(
deps = [
":BottomNavigation",
":ColorThemer",
":Theming",
":TypographyThemer",
":private",
],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2019-present the Material Components for iOS authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#import "MaterialBottomNavigation.h"
#import "MaterialContainerScheme.h"

@interface MDCBottomNavigationBar (MaterialTheming)

/**
Applies the primary theme for a bottom navigation bar to this instance.
@param scheme A container scheme instance containing any desired customizations to the theming
system.
*/
- (void)applyPrimaryThemeWithScheme:(nonnull id<MDCContainerScheming>)scheme;

/**
Applies the surface theme for a bottom navigation bar to this instance.
@param scheme A container scheme instance containing any desired customizations to the theming
system.
*/
- (void)applySurfaceThemeWithScheme:(nonnull id<MDCContainerScheming>)scheme;

@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Copyright 2019-present the Material Components for iOS authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#import "MDCBottomNavigationBar+MaterialTheming.h"

#import "MaterialColorScheme.h"
#import "MaterialShadowElevations.h"
#import "MaterialTypographyScheme.h"

static const CGFloat kUnselectedPrimaryAlpha = 0.74f;
static const CGFloat kUnselectedSurfaceAlpha = 0.6f;

@implementation MDCBottomNavigationBar (MaterialTheming)

- (void)applyPrimaryThemeWithScheme:(nonnull id<MDCContainerScheming>)scheme {
[self applyPrimaryThemeWithColorScheme:scheme.colorScheme];
[self applyThemeWithTypographyScheme:scheme.typographyScheme];
self.elevation = MDCShadowElevationBottomNavigationBar;
self.itemsContentVerticalMargin = 0;
}

- (void)applyPrimaryThemeWithColorScheme:(nonnull id<MDCColorScheming>)colorScheme {
self.barTintColor = colorScheme.primaryColor;
self.selectedItemTintColor = colorScheme.onPrimaryColor;
self.selectedItemTitleColor = colorScheme.onPrimaryColor;
self.unselectedItemTintColor =
[colorScheme.onPrimaryColor colorWithAlphaComponent:kUnselectedPrimaryAlpha];
}

- (void)applySurfaceThemeWithScheme:(nonnull id<MDCContainerScheming>)scheme {
[self applySurfaceThemeWithColorScheme:scheme.colorScheme];
[self applyThemeWithTypographyScheme:scheme.typographyScheme];
self.elevation = MDCShadowElevationBottomNavigationBar;
self.itemsContentVerticalMargin = 0;
}

- (void)applySurfaceThemeWithColorScheme:(nonnull id<MDCColorScheming>)colorScheme {
self.barTintColor = colorScheme.surfaceColor;
self.selectedItemTintColor = colorScheme.primaryColor;
self.selectedItemTitleColor = colorScheme.primaryColor;
self.unselectedItemTintColor =
[colorScheme.onSurfaceColor colorWithAlphaComponent:kUnselectedSurfaceAlpha];
}

- (void)applyThemeWithTypographyScheme:(nonnull id<MDCTypographyScheming>)typographyScheme {
self.itemTitleFont = typographyScheme.caption;
}

@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Copyright 2019-present the Material Components for iOS authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#import "MDCBottomNavigationBar+MaterialTheming.h"
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
// Copyright 2019-present the Material Components for iOS authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#import "MaterialBottomNavigation+Theming.h"

#import <XCTest/XCTest.h>

#import "../../src/private/MDCBottomNavigationItemView.h"
#import "MaterialSnapshot.h"

static const CGFloat kFakeWidth = 500;
static const CGFloat kFakeHeight = 75;

@interface MDCBottomNavigationThemingSnapshotTests : MDCSnapshotTestCase
@property(nonatomic, strong, nullable) MDCBottomNavigationBar *bottomNavigationBar;
@property(nonatomic, strong) UITabBarItem *tabItem1;
@property(nonatomic, strong) UITabBarItem *tabItem2;
@property(nonatomic, strong) UITabBarItem *tabItem3;
@end

@implementation MDCBottomNavigationThemingSnapshotTests

- (void)setUp {
[super setUp];

// Uncomment below to recreate all the goldens (or add the following line to the specific
// test you wish to recreate the golden for).
// self.recordMode = YES;

self.bottomNavigationBar = [[MDCBottomNavigationBar alloc] init];
CGSize imageSize = CGSizeMake(24, 24);
self.tabItem1 = [[UITabBarItem alloc]
initWithTitle:@"Item 1"
image:[UIImage mdc_testImageOfSize:imageSize
withStyle:MDCSnapshotTestImageStyleEllipses]
tag:1];
self.tabItem2 = [[UITabBarItem alloc]
initWithTitle:@"Item 2"
image:[UIImage mdc_testImageOfSize:imageSize
withStyle:MDCSnapshotTestImageStyleCheckerboard]
tag:2];
self.tabItem3 = [[UITabBarItem alloc]
initWithTitle:@"Item 3"
image:[UIImage mdc_testImageOfSize:imageSize
withStyle:MDCSnapshotTestImageStyleFramedX]
tag:3];
self.bottomNavigationBar.items = @[ self.tabItem1, self.tabItem2, self.tabItem3 ];
self.bottomNavigationBar.frame = CGRectMake(0, 0, kFakeWidth, kFakeHeight);
self.bottomNavigationBar.titleVisibility = MDCBottomNavigationBarTitleVisibilityAlways;
}

- (void)tearDown {
self.bottomNavigationBar = nil;
self.tabItem1 = nil;
self.tabItem2 = nil;
self.tabItem3 = nil;

[super tearDown];
}

#pragma mark - Helpers

- (void)generateAndVerifySnapshot {
UIView *backgroundView = [self.bottomNavigationBar mdc_addToBackgroundView];
[self snapshotVerifyView:backgroundView];
}

- (void)performInkTouchOnBar:(MDCBottomNavigationBar *)navigationBar item:(UITabBarItem *)item {
[navigationBar layoutIfNeeded];
MDCBottomNavigationItemView *itemView =
(MDCBottomNavigationItemView *)[self.bottomNavigationBar viewForItem:item];
[itemView.inkView startTouchBeganAtPoint:CGPointMake(CGRectGetMidX(itemView.bounds),
CGRectGetMidY(itemView.bounds))
animated:NO
withCompletion:nil];
}

- (MDCTypographyScheme *)customTypographyScheme {
MDCTypographyScheme *typographyScheme = [[MDCTypographyScheme alloc] init];
typographyScheme.headline1 = [UIFont systemFontOfSize:10];
typographyScheme.headline2 = [UIFont systemFontOfSize:11];
typographyScheme.headline3 = [UIFont systemFontOfSize:12];
typographyScheme.headline4 = [UIFont systemFontOfSize:13];
typographyScheme.headline5 = [UIFont systemFontOfSize:14];
typographyScheme.headline6 = [UIFont systemFontOfSize:15];
typographyScheme.subtitle1 = [UIFont systemFontOfSize:16];
typographyScheme.subtitle2 = [UIFont systemFontOfSize:17];
typographyScheme.body1 = [UIFont systemFontOfSize:18];
typographyScheme.body2 = [UIFont systemFontOfSize:19];
typographyScheme.caption = [UIFont systemFontOfSize:20];
typographyScheme.button = [UIFont systemFontOfSize:21];
typographyScheme.overline = [UIFont systemFontOfSize:22];
return typographyScheme;
}

- (MDCSemanticColorScheme *)customColorScheme {
MDCSemanticColorScheme *colorScheme = [[MDCSemanticColorScheme alloc] init];
colorScheme.primaryColor = UIColor.blueColor;
colorScheme.primaryColorVariant = UIColor.greenColor;
colorScheme.secondaryColor = UIColor.redColor;
colorScheme.errorColor = UIColor.brownColor;
colorScheme.surfaceColor = UIColor.cyanColor;
colorScheme.backgroundColor = UIColor.grayColor;
colorScheme.onPrimaryColor = UIColor.magentaColor;
colorScheme.onSecondaryColor = UIColor.orangeColor;
colorScheme.onSurfaceColor = UIColor.purpleColor;
colorScheme.onBackgroundColor = UIColor.yellowColor;
return colorScheme;
}

- (void)testPrimaryThemeWithDefaultContainerScheme {
// Given
MDCBottomNavigationBar *bottomNav = self.bottomNavigationBar;
MDCContainerScheme *containerScheme = [[MDCContainerScheme alloc] init];

// When
[bottomNav applyPrimaryThemeWithScheme:containerScheme];
[self performInkTouchOnBar:bottomNav item:self.tabItem1];

// Then
[self generateAndVerifySnapshot];
}

- (void)testPrimaryThemeWithCustomContainerScheme {
// Given
MDCBottomNavigationBar *bottomNav = self.bottomNavigationBar;
MDCContainerScheme *containerScheme = [[MDCContainerScheme alloc] init];
containerScheme.typographyScheme = [self customTypographyScheme];
containerScheme.colorScheme = [self customColorScheme];

// When
[bottomNav applyPrimaryThemeWithScheme:containerScheme];

// Then
[self generateAndVerifySnapshot];
}

- (void)testSurfaceThemeWithDefaultScheme {
// Given
MDCBottomNavigationBar *bottomNav = self.bottomNavigationBar;
MDCContainerScheme *containerScheme = [[MDCContainerScheme alloc] init];

// When
[bottomNav applySurfaceThemeWithScheme:containerScheme];
[self performInkTouchOnBar:bottomNav item:self.tabItem1];

// Then
[self generateAndVerifySnapshot];
}

- (void)testSurfaceThemeWithCustomContainerScheme {
// Given
MDCBottomNavigationBar *bottomNav = self.bottomNavigationBar;
MDCContainerScheme *containerScheme = [[MDCContainerScheme alloc] init];
containerScheme.typographyScheme = [self customTypographyScheme];
containerScheme.colorScheme = [self customColorScheme];

// When
[bottomNav applySurfaceThemeWithScheme:containerScheme];

// Then
[self generateAndVerifySnapshot];
}

@end

0 comments on commit f7ac1db

Please sign in to comment.