Browse Source

Create new UITabBarItem instance on each bottomTab update (#6018)

Fix an issue where bottomTab.testID doesn't get updated on mergeOptions unless a new UITabBarItem is created. Look like an issue in iOS where tabBarItem.accessibilityIdentifier doesn't get updated unless a new tabBarItem is created.
Yogev Ben David 4 years ago
parent
commit
3757ff7aa6
No account linked to committer's email address

+ 0
- 2
lib/ios/BottomTabAppearancePresenter.h View File

3
 API_AVAILABLE(ios(13.0))
3
 API_AVAILABLE(ios(13.0))
4
 @interface BottomTabAppearancePresenter : BottomTabPresenter
4
 @interface BottomTabAppearancePresenter : BottomTabPresenter
5
 
5
 
6
-- (instancetype)initWithDefaultOptions:(RNNNavigationOptions *)defaultOptions children:(NSArray<UIViewController *> *)children;
7
-
8
 @end
6
 @end

+ 1
- 9
lib/ios/BottomTabAppearancePresenter.m View File

3
 
3
 
4
 @implementation BottomTabAppearancePresenter
4
 @implementation BottomTabAppearancePresenter
5
 
5
 
6
-- (instancetype)initWithDefaultOptions:(RNNNavigationOptions *)defaultOptions children:(NSArray<UIViewController *> *)children {
7
-    self = [super initWithDefaultOptions:defaultOptions];
8
-    for (UIViewController* child in children) {
9
-        child.tabBarItem.standardAppearance = [[UITabBarAppearance alloc] init];
10
-    }
11
-    return self;
12
-}
13
-
14
 - (void)createTabBarItem:(UIViewController *)child bottomTabOptions:(RNNBottomTabOptions *)bottomTabOptions {
6
 - (void)createTabBarItem:(UIViewController *)child bottomTabOptions:(RNNBottomTabOptions *)bottomTabOptions {
15
-    child.tabBarItem = [TabBarItemAppearanceCreator updateTabBarItem:child.tabBarItem bottomTabOptions:bottomTabOptions];
7
+    child.tabBarItem = [TabBarItemAppearanceCreator createTabBarItem:bottomTabOptions mergeItem:child.tabBarItem];
16
 }
8
 }
17
 
9
 
18
 @end
10
 @end

+ 3
- 3
lib/ios/BottomTabPresenter.m View File

15
 - (void)applyOptionsOnWillMoveToParentViewController:(RNNNavigationOptions *)options  child:(UIViewController *)child {
15
 - (void)applyOptionsOnWillMoveToParentViewController:(RNNNavigationOptions *)options  child:(UIViewController *)child {
16
     RNNNavigationOptions * withDefault = [options withDefault:self.defaultOptions];
16
     RNNNavigationOptions * withDefault = [options withDefault:self.defaultOptions];
17
     
17
     
18
+    [self createTabBarItem:child bottomTabOptions:withDefault.bottomTab];
18
     [child setTabBarItemBadge:[withDefault.bottomTab.badge getWithDefaultValue:[NSNull null]]];
19
     [child setTabBarItemBadge:[withDefault.bottomTab.badge getWithDefaultValue:[NSNull null]]];
19
     [child setTabBarItemBadgeColor:[withDefault.bottomTab.badgeColor getWithDefaultValue:nil]];
20
     [child setTabBarItemBadgeColor:[withDefault.bottomTab.badgeColor getWithDefaultValue:nil]];
20
-    [self createTabBarItem:child bottomTabOptions:withDefault.bottomTab];
21
 }
21
 }
22
 
22
 
23
 - (void)mergeOptions:(RNNNavigationOptions *)options resolvedOptions:(RNNNavigationOptions *)resolvedOptions child:(UIViewController *)child {
23
 - (void)mergeOptions:(RNNNavigationOptions *)options resolvedOptions:(RNNNavigationOptions *)resolvedOptions child:(UIViewController *)child {
24
     RNNNavigationOptions* withDefault = (RNNNavigationOptions *) [[resolvedOptions withDefault:self.defaultOptions] overrideOptions:options];
24
     RNNNavigationOptions* withDefault = (RNNNavigationOptions *) [[resolvedOptions withDefault:self.defaultOptions] overrideOptions:options];
25
     
25
     
26
+    if (options.bottomTab.hasValue) [self createTabBarItem:child bottomTabOptions:withDefault.bottomTab];
26
     if (options.bottomTab.badge.hasValue) [child setTabBarItemBadge:options.bottomTab.badge.get];
27
     if (options.bottomTab.badge.hasValue) [child setTabBarItemBadge:options.bottomTab.badge.get];
27
     if (options.bottomTab.badgeColor.hasValue) [child setTabBarItemBadgeColor:options.bottomTab.badgeColor.get];
28
     if (options.bottomTab.badgeColor.hasValue) [child setTabBarItemBadgeColor:options.bottomTab.badgeColor.get];
28
-    if (options.bottomTab.hasValue) [self createTabBarItem:child bottomTabOptions:withDefault.bottomTab];
29
 }
29
 }
30
 
30
 
31
 - (void)createTabBarItem:(UIViewController *)child bottomTabOptions:(RNNBottomTabOptions *)bottomTabOptions {
31
 - (void)createTabBarItem:(UIViewController *)child bottomTabOptions:(RNNBottomTabOptions *)bottomTabOptions {
32
-    child.tabBarItem = [RNNTabBarItemCreator updateTabBarItem:child.tabBarItem bottomTabOptions:bottomTabOptions];
32
+    child.tabBarItem = [RNNTabBarItemCreator createTabBarItem:bottomTabOptions mergeItem:child.tabBarItem];
33
 }
33
 }
34
 
34
 
35
 @end
35
 @end

+ 1
- 1
lib/ios/BottomTabPresenterCreator.h View File

3
 
3
 
4
 @interface BottomTabPresenterCreator : NSObject
4
 @interface BottomTabPresenterCreator : NSObject
5
 
5
 
6
-+ (BottomTabPresenter *)createWithDefaultOptions:(RNNNavigationOptions *)defaultOptions children:(NSArray<UIViewController *> *)children;
6
++ (BottomTabPresenter *)createWithDefaultOptions:(RNNNavigationOptions *)defaultOptions;
7
 
7
 
8
 @end
8
 @end

+ 2
- 2
lib/ios/BottomTabPresenterCreator.m View File

3
 
3
 
4
 @implementation BottomTabPresenterCreator
4
 @implementation BottomTabPresenterCreator
5
 
5
 
6
-+ (BottomTabPresenter *)createWithDefaultOptions:(RNNNavigationOptions *)defaultOptions children:(NSArray<UIViewController *> *)children {
6
++ (BottomTabPresenter *)createWithDefaultOptions:(RNNNavigationOptions *)defaultOptions {
7
 	if (@available(iOS 13.0, *)) {
7
 	if (@available(iOS 13.0, *)) {
8
-		return [[BottomTabAppearancePresenter alloc] initWithDefaultOptions:defaultOptions children:children];
8
+		return [[BottomTabAppearancePresenter alloc] initWithDefaultOptions:defaultOptions];
9
 	} else {
9
 	} else {
10
 		return [[BottomTabPresenter alloc] initWithDefaultOptions:defaultOptions];
10
 		return [[BottomTabPresenter alloc] initWithDefaultOptions:defaultOptions];
11
 	}
11
 	}

+ 1
- 1
lib/ios/RNNControllerFactory.m View File

152
     RNNNavigationOptions* options = [[RNNNavigationOptions alloc] initWithDict:node.data[@"options"]];
152
     RNNNavigationOptions* options = [[RNNNavigationOptions alloc] initWithDict:node.data[@"options"]];
153
     RNNBottomTabsPresenter* presenter = [BottomTabsPresenterCreator createWithDefaultOptions:_defaultOptions];
153
     RNNBottomTabsPresenter* presenter = [BottomTabsPresenterCreator createWithDefaultOptions:_defaultOptions];
154
     NSArray *childViewControllers = [self extractChildrenViewControllersFromNode:node];
154
     NSArray *childViewControllers = [self extractChildrenViewControllersFromNode:node];
155
-    BottomTabPresenter* bottomTabPresenter = [BottomTabPresenterCreator createWithDefaultOptions:_defaultOptions children:childViewControllers];;
155
+    BottomTabPresenter* bottomTabPresenter = [BottomTabPresenterCreator createWithDefaultOptions:_defaultOptions];
156
     RNNDotIndicatorPresenter* dotIndicatorPresenter = [[RNNDotIndicatorPresenter alloc] initWithDefaultOptions:_defaultOptions];
156
     RNNDotIndicatorPresenter* dotIndicatorPresenter = [[RNNDotIndicatorPresenter alloc] initWithDefaultOptions:_defaultOptions];
157
 	BottomTabsBaseAttacher* bottomTabsAttacher = [_bottomTabsAttachModeFactory fromOptions:options];
157
 	BottomTabsBaseAttacher* bottomTabsAttacher = [_bottomTabsAttachModeFactory fromOptions:options];
158
     
158
     

+ 3
- 1
lib/ios/RNNTabBarItemCreator.h View File

4
 
4
 
5
 @interface RNNTabBarItemCreator : NSObject
5
 @interface RNNTabBarItemCreator : NSObject
6
 
6
 
7
-+ (UITabBarItem *)updateTabBarItem:(UITabBarItem *)tabItem bottomTabOptions:(RNNBottomTabOptions *)bottomTabOptions;
7
++ (UITabBarItem *)createTabBarItem:(RNNBottomTabOptions *)bottomTabOptions mergeItem:(UITabBarItem *)mergeItem;
8
+
9
++ (UITabBarItem *)createTabBarItem:(UITabBarItem *)mergeItem;
8
 
10
 
9
 + (void)setTitleAttributes:(UITabBarItem *)tabItem titleAttributes:(NSDictionary *)titleAttributes;
11
 + (void)setTitleAttributes:(UITabBarItem *)tabItem titleAttributes:(NSDictionary *)titleAttributes;
10
 
12
 

+ 6
- 1
lib/ios/RNNTabBarItemCreator.m View File

4
 
4
 
5
 @implementation RNNTabBarItemCreator
5
 @implementation RNNTabBarItemCreator
6
 
6
 
7
-+ (UITabBarItem *)updateTabBarItem:(UITabBarItem *)tabItem bottomTabOptions:(RNNBottomTabOptions *)bottomTabOptions {
7
++ (UITabBarItem *)createTabBarItem:(UITabBarItem *)mergeItem {
8
+    return [UITabBarItem new];
9
+}
10
+
11
++ (UITabBarItem *)createTabBarItem:(RNNBottomTabOptions *)bottomTabOptions mergeItem:(UITabBarItem *)mergeItem {
12
+    UITabBarItem* tabItem = [self createTabBarItem:mergeItem];
8
 	UIImage* icon = [bottomTabOptions.icon getWithDefaultValue:nil];
13
 	UIImage* icon = [bottomTabOptions.icon getWithDefaultValue:nil];
9
 	UIImage* selectedIcon = [bottomTabOptions.selectedIcon getWithDefaultValue:icon];
14
 	UIImage* selectedIcon = [bottomTabOptions.selectedIcon getWithDefaultValue:icon];
10
 	UIColor* iconColor = [bottomTabOptions.iconColor getWithDefaultValue:nil];
15
 	UIColor* iconColor = [bottomTabOptions.iconColor getWithDefaultValue:nil];

+ 1
- 0
lib/ios/TabBarItemAppearanceCreator.h View File

1
 #import "RNNTabBarItemCreator.h"
1
 #import "RNNTabBarItemCreator.h"
2
 
2
 
3
+API_AVAILABLE(ios(13.0))
3
 @interface TabBarItemAppearanceCreator : RNNTabBarItemCreator
4
 @interface TabBarItemAppearanceCreator : RNNTabBarItemCreator
4
 
5
 
5
 @end
6
 @end

+ 6
- 0
lib/ios/TabBarItemAppearanceCreator.m View File

2
 
2
 
3
 @implementation TabBarItemAppearanceCreator
3
 @implementation TabBarItemAppearanceCreator
4
 
4
 
5
++ (UITabBarItem *)createTabBarItem:(UITabBarItem *)mergeItem {
6
+    UITabBarItem* tabBarItem = [super createTabBarItem:mergeItem];
7
+    tabBarItem.standardAppearance = mergeItem.standardAppearance ?: [[UITabBarAppearance alloc] init];
8
+    return tabBarItem;
9
+}
10
+
5
 + (void)setTitleAttributes:(UITabBarItem *)tabItem titleAttributes:(NSDictionary *)titleAttributes {
11
 + (void)setTitleAttributes:(UITabBarItem *)tabItem titleAttributes:(NSDictionary *)titleAttributes {
6
     tabItem.standardAppearance.stackedLayoutAppearance.normal.titleTextAttributes = titleAttributes;
12
     tabItem.standardAppearance.stackedLayoutAppearance.normal.titleTextAttributes = titleAttributes;
7
 }
13
 }

+ 14
- 0
playground/ios/NavigationTests/BottomTabPresenterTest.m View File

52
 	XCTAssertEqual(self.componentViewController.tabBarItem.title, @"title");
52
 	XCTAssertEqual(self.componentViewController.tabBarItem.title, @"title");
53
 }
53
 }
54
 
54
 
55
+- (void)testMergeOptions_shouldCreateNewTabBarItemInstance {
56
+	RNNNavigationOptions* defaultOptions = [[RNNNavigationOptions alloc] initEmptyOptions];
57
+	defaultOptions.bottomTab.selectedIconColor = [Color withColor:UIColor.greenColor];
58
+	self.uut.defaultOptions = defaultOptions;
59
+	
60
+	RNNNavigationOptions* mergeOptions = [[RNNNavigationOptions alloc] initEmptyOptions];
61
+	mergeOptions.bottomTab.text = [[Text alloc] initWithValue:@"title"];
62
+	
63
+	UITabBarItem* currentTabBarItem = self.componentViewController.tabBarItem;
64
+	[self.uut mergeOptions:mergeOptions resolvedOptions:self.options child:self.componentViewController];
65
+	UITabBarItem* newTabBarItem = self.componentViewController.tabBarItem;
66
+	XCTAssertNotEqual(currentTabBarItem, newTabBarItem);
67
+}
68
+
55
 @end
69
 @end

+ 1
- 1
playground/ios/NavigationTests/RNNBottomTabsAppearancePresenterTest.m View File

25
 	self.children = @[[[RNNComponentViewController alloc] initWithLayoutInfo:nil rootViewCreator:nil eventEmitter:nil presenter:[[RNNComponentPresenter alloc] initWithDefaultOptions:nil] options:nil defaultOptions:nil]];
25
 	self.children = @[[[RNNComponentViewController alloc] initWithLayoutInfo:nil rootViewCreator:nil eventEmitter:nil presenter:[[RNNComponentPresenter alloc] initWithDefaultOptions:nil] options:nil defaultOptions:nil]];
26
 	self.dotIndicatorPresenter = [OCMockObject partialMockForObject:[[RNNDotIndicatorPresenter alloc] initWithDefaultOptions:nil]];
26
 	self.dotIndicatorPresenter = [OCMockObject partialMockForObject:[[RNNDotIndicatorPresenter alloc] initWithDefaultOptions:nil]];
27
     self.uut = [OCMockObject partialMockForObject:[BottomTabsPresenterCreator createWithDefaultOptions:nil]];
27
     self.uut = [OCMockObject partialMockForObject:[BottomTabsPresenterCreator createWithDefaultOptions:nil]];
28
-	self.boundViewController = [OCMockObject partialMockForObject:[[RNNBottomTabsController alloc] initWithLayoutInfo:nil creator:nil options:nil defaultOptions:nil presenter:self.uut bottomTabPresenter:[BottomTabPresenterCreator createWithDefaultOptions:nil children:self.children] dotIndicatorPresenter:self.dotIndicatorPresenter eventEmitter:nil childViewControllers:self.children bottomTabsAttacher:nil]];
28
+	self.boundViewController = [OCMockObject partialMockForObject:[[RNNBottomTabsController alloc] initWithLayoutInfo:nil creator:nil options:nil defaultOptions:nil presenter:self.uut bottomTabPresenter:[BottomTabPresenterCreator createWithDefaultOptions:nil] dotIndicatorPresenter:self.dotIndicatorPresenter eventEmitter:nil childViewControllers:self.children bottomTabsAttacher:nil]];
29
     [self.uut bindViewController:self.boundViewController];
29
     [self.uut bindViewController:self.boundViewController];
30
     self.options = [[RNNNavigationOptions alloc] initEmptyOptions];
30
     self.options = [[RNNNavigationOptions alloc] initEmptyOptions];
31
 }
31
 }

+ 1
- 1
playground/ios/NavigationTests/RNNBottomTabsController+Helpers.m View File

11
 
11
 
12
 + (RNNBottomTabsController *)createWithChildren:(NSArray *)children {
12
 + (RNNBottomTabsController *)createWithChildren:(NSArray *)children {
13
 	RNNNavigationOptions* defaultOptions = [[RNNNavigationOptions alloc] initEmptyOptions];
13
 	RNNNavigationOptions* defaultOptions = [[RNNNavigationOptions alloc] initEmptyOptions];
14
-	return [[RNNBottomTabsController alloc] initWithLayoutInfo:nil creator:nil options:[[RNNNavigationOptions alloc] initEmptyOptions] defaultOptions:defaultOptions presenter:[BottomTabsPresenterCreator createWithDefaultOptions:defaultOptions] bottomTabPresenter:[BottomTabPresenterCreator createWithDefaultOptions:defaultOptions children:children] dotIndicatorPresenter:[[RNNDotIndicatorPresenter alloc] initWithDefaultOptions:defaultOptions] eventEmitter:nil childViewControllers:children bottomTabsAttacher:nil];
14
+	return [[RNNBottomTabsController alloc] initWithLayoutInfo:nil creator:nil options:[[RNNNavigationOptions alloc] initEmptyOptions] defaultOptions:defaultOptions presenter:[BottomTabsPresenterCreator createWithDefaultOptions:defaultOptions] bottomTabPresenter:[BottomTabPresenterCreator createWithDefaultOptions:defaultOptions] dotIndicatorPresenter:[[RNNDotIndicatorPresenter alloc] initWithDefaultOptions:defaultOptions] eventEmitter:nil childViewControllers:children bottomTabsAttacher:nil];
15
 }
15
 }
16
 
16
 
17
 @end
17
 @end

+ 1
- 1
playground/ios/NavigationTests/RNNDotIndicatorPresenterTest.m View File

20
 - (void)setUp {
20
 - (void)setUp {
21
     [super setUp];
21
     [super setUp];
22
 	self.child = [self createChild];
22
 	self.child = [self createChild];
23
-	self.bottomTabPresenter = [BottomTabPresenterCreator createWithDefaultOptions:nil children:@[self.child]];
23
+	self.bottomTabPresenter = [BottomTabPresenterCreator createWithDefaultOptions:nil];
24
     self.uut = [OCMockObject partialMockForObject:[RNNDotIndicatorPresenter new]];
24
     self.uut = [OCMockObject partialMockForObject:[RNNDotIndicatorPresenter new]];
25
     self.bottomTabs = [OCMockObject partialMockForObject:[RNNBottomTabsController createWithChildren:@[self.child]]];
25
     self.bottomTabs = [OCMockObject partialMockForObject:[RNNBottomTabsController createWithChildren:@[self.child]]];
26
 
26
 

+ 0
- 2
playground/ios/NavigationTests/RNNRootViewControllerTest.m View File

180
 	NSString* tabBadgeInput = @"5";
180
 	NSString* tabBadgeInput = @"5";
181
 	self.options.bottomTab.badge = [[Text alloc] initWithValue:tabBadgeInput];
181
 	self.options.bottomTab.badge = [[Text alloc] initWithValue:tabBadgeInput];
182
 	NSMutableArray* controllers = [NSMutableArray new];
182
 	NSMutableArray* controllers = [NSMutableArray new];
183
-	UITabBarItem* item = [[UITabBarItem alloc] initWithTitle:@"A Tab" image:nil tag:1];
184
-	[self.uut setTabBarItem:item];
185
 	[controllers addObject:self.uut];
183
 	[controllers addObject:self.uut];
186
 	__unused RNNBottomTabsController* vc = [RNNBottomTabsController createWithChildren:controllers];
184
 	__unused RNNBottomTabsController* vc = [RNNBottomTabsController createWithChildren:controllers];
187
 	[self.uut willMoveToParentViewController:vc];
185
 	[self.uut willMoveToParentViewController:vc];

+ 1
- 1
playground/ios/NavigationTests/RNNTabBarControllerTest.m View File

28
     self.mockTabBarPresenter = [OCMockObject partialMockForObject:[[RNNBottomTabsPresenter alloc] init]];
28
     self.mockTabBarPresenter = [OCMockObject partialMockForObject:[[RNNBottomTabsPresenter alloc] init]];
29
     self.mockChildViewController = [OCMockObject partialMockForObject:[RNNComponentViewController new]];
29
     self.mockChildViewController = [OCMockObject partialMockForObject:[RNNComponentViewController new]];
30
     self.mockEventEmitter = [OCMockObject partialMockForObject:[RNNEventEmitter new]];
30
     self.mockEventEmitter = [OCMockObject partialMockForObject:[RNNEventEmitter new]];
31
-	self.originalUut = [[RNNBottomTabsController alloc] initWithLayoutInfo:nil creator:nil options:[[RNNNavigationOptions alloc] initWithDict:@{}] defaultOptions:nil presenter:self.mockTabBarPresenter bottomTabPresenter:[BottomTabPresenterCreator createWithDefaultOptions:nil children:children] dotIndicatorPresenter:[[RNNDotIndicatorPresenter alloc] initWithDefaultOptions:nil] eventEmitter:self.mockEventEmitter childViewControllers:children bottomTabsAttacher:nil];
31
+	self.originalUut = [[RNNBottomTabsController alloc] initWithLayoutInfo:nil creator:nil options:[[RNNNavigationOptions alloc] initWithDict:@{}] defaultOptions:nil presenter:self.mockTabBarPresenter bottomTabPresenter:[BottomTabPresenterCreator createWithDefaultOptions:nil] dotIndicatorPresenter:[[RNNDotIndicatorPresenter alloc] initWithDefaultOptions:nil] eventEmitter:self.mockEventEmitter childViewControllers:children bottomTabsAttacher:nil];
32
     self.uut = [OCMockObject partialMockForObject:self.originalUut];
32
     self.uut = [OCMockObject partialMockForObject:self.originalUut];
33
     OCMStub([self.uut selectedViewController]).andReturn(self.mockChildViewController);
33
     OCMStub([self.uut selectedViewController]).andReturn(self.mockChildViewController);
34
 }
34
 }