Browse Source

Fix back button on iOS 13 (#5703)

Yogev Ben David 4 years ago
parent
commit
ed7c5795e1
No account linked to committer's email address

+ 0
- 9
lib/ios/RNNComponentPresenter.m View File

28
 
28
 
29
 - (void)applyOptionsOnWillMoveToParentViewController:(RNNNavigationOptions *)options {
29
 - (void)applyOptionsOnWillMoveToParentViewController:(RNNNavigationOptions *)options {
30
 	[super applyOptionsOnWillMoveToParentViewController:options];
30
 	[super applyOptionsOnWillMoveToParentViewController:options];
31
-	UIViewController* viewController = self.boundViewController;
32
-	RNNNavigationOptions *withDefault = [options withDefault:[self defaultOptions]];
33
-	[viewController setBackButtonIcon:[withDefault.topBar.backButton.icon getWithDefaultValue:nil] withColor:[withDefault.topBar.backButton.color getWithDefaultValue:nil] title:[withDefault.topBar.backButton.showTitle getWithDefaultValue:YES] ? [withDefault.topBar.backButton.title getWithDefaultValue:nil] : @""];
34
 }
31
 }
35
 
32
 
36
 - (void)applyOptions:(RNNNavigationOptions *)options {
33
 - (void)applyOptions:(RNNNavigationOptions *)options {
158
 	}
155
 	}
159
 
156
 
160
 	[self setTitleViewWithSubtitle:withDefault];
157
 	[self setTitleViewWithSubtitle:withDefault];
161
-	
162
-	if (options.topBar.backButton.hasValue) {
163
-		UIViewController *lastViewControllerInStack = viewController.navigationController.viewControllers.count > 1 ? viewController.navigationController.viewControllers[viewController.navigationController.viewControllers.count - 2] : viewController.navigationController.topViewController;
164
-	    RNNNavigationOptions * resolvedOptions	= (RNNNavigationOptions *) [[currentOptions overrideOptions:options] withDefault:[self defaultOptions]];
165
-		[lastViewControllerInStack applyBackButton:resolvedOptions.topBar.backButton];
166
-	}
167
 }
158
 }
168
 
159
 
169
 - (void)removeTitleComponentIfNeeded:(RNNNavigationOptions *)options {
160
 - (void)removeTitleComponentIfNeeded:(RNNNavigationOptions *)options {

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

44
 	[stack setNavigationBarLargeTitleFontFamily:[withDefault.topBar.largeTitle.fontFamily getWithDefaultValue:nil] fontSize:[withDefault.topBar.largeTitle.fontSize getWithDefaultValue:nil] fontWeight:[withDefault.topBar.largeTitle.fontWeight getWithDefaultValue:nil] color:[withDefault.topBar.largeTitle.color getWithDefaultValue:nil]];
44
 	[stack setNavigationBarLargeTitleFontFamily:[withDefault.topBar.largeTitle.fontFamily getWithDefaultValue:nil] fontSize:[withDefault.topBar.largeTitle.fontSize getWithDefaultValue:nil] fontWeight:[withDefault.topBar.largeTitle.fontWeight getWithDefaultValue:nil] color:[withDefault.topBar.largeTitle.color getWithDefaultValue:nil]];
45
 	[stack setNavigationBarFontFamily:[withDefault.topBar.title.fontFamily getWithDefaultValue:nil] fontSize:[withDefault.topBar.title.fontSize getWithDefaultValue:nil] fontWeight:[withDefault.topBar.title.fontWeight getWithDefaultValue:nil] color:[withDefault.topBar.title.color getWithDefaultValue:nil]];
45
 	[stack setNavigationBarFontFamily:[withDefault.topBar.title.fontFamily getWithDefaultValue:nil] fontSize:[withDefault.topBar.title.fontSize getWithDefaultValue:nil] fontWeight:[withDefault.topBar.title.fontWeight getWithDefaultValue:nil] color:[withDefault.topBar.title.color getWithDefaultValue:nil]];
46
 	[stack setBackButtonColor:[withDefault.topBar.backButton.color getWithDefaultValue:nil]];
46
 	[stack setBackButtonColor:[withDefault.topBar.backButton.color getWithDefaultValue:nil]];
47
+    [stack setBackButtonIcon:[withDefault.topBar.backButton.icon getWithDefaultValue:nil] withColor:[withDefault.topBar.backButton.color getWithDefaultValue:nil] title:[withDefault.topBar.backButton.title getWithDefaultValue:nil] showTitle:[withDefault.topBar.backButton.showTitle getWithDefaultValue:YES]];
47
 }
48
 }
48
 
49
 
49
 - (void)applyOptionsOnViewDidLayoutSubviews:(RNNNavigationOptions *)options {
50
 - (void)applyOptionsOnViewDidLayoutSubviews:(RNNNavigationOptions *)options {
59
 	[navigationController setTopBarBackgroundColor:[withDefault.topBar.background.color getWithDefaultValue:nil]];
60
 	[navigationController setTopBarBackgroundColor:[withDefault.topBar.background.color getWithDefaultValue:nil]];
60
 	[navigationController setNavigationBarFontFamily:[withDefault.topBar.title.fontFamily getWithDefaultValue:nil] fontSize:[withDefault.topBar.title.fontSize getWithDefaultValue:nil] fontWeight:[withDefault.topBar.title.fontWeight getWithDefaultValue:nil] color:[withDefault.topBar.title.color getWithDefaultValue:nil]];
61
 	[navigationController setNavigationBarFontFamily:[withDefault.topBar.title.fontFamily getWithDefaultValue:nil] fontSize:[withDefault.topBar.title.fontSize getWithDefaultValue:nil] fontWeight:[withDefault.topBar.title.fontWeight getWithDefaultValue:nil] color:[withDefault.topBar.title.color getWithDefaultValue:nil]];
61
 	[navigationController setNavigationBarLargeTitleVisible:[withDefault.topBar.largeTitle.visible getWithDefaultValue:NO]];
62
 	[navigationController setNavigationBarLargeTitleVisible:[withDefault.topBar.largeTitle.visible getWithDefaultValue:NO]];
63
+    [navigationController setBackButtonIcon:[withDefault.topBar.backButton.icon getWithDefaultValue:nil] withColor:[withDefault.topBar.backButton.color getWithDefaultValue:nil] title:[withDefault.topBar.backButton.title getWithDefaultValue:nil] showTitle:[withDefault.topBar.backButton.showTitle getWithDefaultValue:YES]];
62
 }
64
 }
63
 
65
 
64
 - (void)mergeOptions:(RNNNavigationOptions *)options resolvedOptions:(RNNNavigationOptions *)resolvedOptions {
66
 - (void)mergeOptions:(RNNNavigationOptions *)options resolvedOptions:(RNNNavigationOptions *)resolvedOptions {
135
 	if (options.topBar.background.component.name.hasValue) {
137
 	if (options.topBar.background.component.name.hasValue) {
136
 		[self setCustomNavigationComponentBackground:options perform:nil];
138
 		[self setCustomNavigationComponentBackground:options perform:nil];
137
 	}
139
 	}
140
+    
141
+    if (options.topBar.backButton.hasValue) {
142
+        [stack setBackButtonIcon:[withDefault.topBar.backButton.icon getWithDefaultValue:nil] withColor:[withDefault.topBar.backButton.color getWithDefaultValue:nil] title:[withDefault.topBar.backButton.title getWithDefaultValue:nil] showTitle:[withDefault.topBar.backButton.showTitle getWithDefaultValue:YES]];
143
+    }
138
 }
144
 }
139
 
145
 
140
 - (void)renderComponents:(RNNNavigationOptions *)options perform:(RNNReactViewReadyCompletionBlock)readyBlock {
146
 - (void)renderComponents:(RNNNavigationOptions *)options perform:(RNNReactViewReadyCompletionBlock)readyBlock {

+ 2
- 0
lib/ios/UINavigationBar+utils.h View File

6
 
6
 
7
 - (void)rnn_setBackgroundColorTransparent;
7
 - (void)rnn_setBackgroundColorTransparent;
8
 
8
 
9
+- (void)rnn_setBackIndicatorImage:(UIImage *)image;
10
+
9
 @end
11
 @end

+ 10
- 0
lib/ios/UINavigationBar+utils.m View File

57
     }
57
     }
58
 }
58
 }
59
 
59
 
60
+- (void)rnn_setBackIndicatorImage:(UIImage *)image {
61
+    if (@available(iOS 13.0, *)) {
62
+        [[self getNavigaitonBarStandardAppearance] setBackIndicatorImage:image transitionMaskImage:image];
63
+        [[self getNavigaitonBarCompactAppearance] setBackIndicatorImage:image transitionMaskImage:image];
64
+        [[self getNavigaitonBarScrollEdgeAppearance] setBackIndicatorImage:image transitionMaskImage:image];
65
+    } else {
66
+        [self setBackIndicatorImage:image];
67
+        [self setBackIndicatorTransitionMaskImage:image];
68
+    }
69
+}
60
 
70
 
61
 - (UINavigationBarAppearance*)getNavigaitonBarStandardAppearance  API_AVAILABLE(ios(13.0)) {
71
 - (UINavigationBarAppearance*)getNavigaitonBarStandardAppearance  API_AVAILABLE(ios(13.0)) {
62
     if (!self.standardAppearance) {
72
     if (!self.standardAppearance) {

+ 2
- 0
lib/ios/UINavigationController+RNNOptions.h View File

30
 
30
 
31
 - (void)setBackButtonColor:(UIColor *)color;
31
 - (void)setBackButtonColor:(UIColor *)color;
32
 
32
 
33
+- (void)setBackButtonIcon:(UIImage *)icon withColor:(UIColor *)color title:(NSString *)title showTitle:(BOOL)showTitle;
34
+
33
 @end
35
 @end

+ 22
- 0
lib/ios/UINavigationController+RNNOptions.m View File

1
 #import "UINavigationController+RNNOptions.h"
1
 #import "UINavigationController+RNNOptions.h"
2
 #import "RNNFontAttributesCreator.h"
2
 #import "RNNFontAttributesCreator.h"
3
+#import "UIImage+tint.h"
4
+#import "UINavigationBar+utils.h"
3
 
5
 
4
 const NSInteger BLUR_TOPBAR_TAG = 78264802;
6
 const NSInteger BLUR_TOPBAR_TAG = 78264802;
5
 
7
 
103
 	self.navigationBar.clipsToBounds = clipsToBounds;
105
 	self.navigationBar.clipsToBounds = clipsToBounds;
104
 }
106
 }
105
 
107
 
108
+- (void)setBackButtonIcon:(UIImage *)icon withColor:(UIColor *)color title:(NSString *)title showTitle:(BOOL)showTitle {
109
+    UIBarButtonItem *backItem = [[UIBarButtonItem alloc] init];
110
+    if (icon) {
111
+        icon = color
112
+        ? [[icon withTintColor:color] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]
113
+        : icon;
114
+    }
115
+    
116
+    [self.navigationBar rnn_setBackIndicatorImage:icon];
117
+
118
+    UIViewController *lastViewControllerInStack = self.viewControllers.count > 1 ? self.viewControllers[self.viewControllers.count - 2] : self.topViewController;
119
+
120
+    if (showTitle) {
121
+        backItem.title = title ? title : lastViewControllerInStack.navigationItem.title;
122
+    }
123
+    backItem.tintColor = color;
124
+
125
+    lastViewControllerInStack.navigationItem.backBarButtonItem = backItem;
126
+}
127
+
106
 @end
128
 @end

+ 0
- 2
lib/ios/UIViewController+RNNOptions.h View File

34
 
34
 
35
 - (void)setInterceptTouchOutside:(BOOL)interceptTouchOutside;
35
 - (void)setInterceptTouchOutside:(BOOL)interceptTouchOutside;
36
 
36
 
37
-- (void)setBackButtonIcon:(UIImage *)icon withColor:(UIColor *)color title:(NSString *)title;
38
-
39
 - (void)applyBackButton:(RNNBackButtonOptions *)backButton;
37
 - (void)applyBackButton:(RNNBackButtonOptions *)backButton;
40
 
38
 
41
 - (BOOL)isModal;
39
 - (BOOL)isModal;

+ 1
- 19
lib/ios/UIViewController+RNNOptions.m View File

1
 #import "UIViewController+RNNOptions.h"
1
 #import "UIViewController+RNNOptions.h"
2
 #import <React/RCTRootView.h>
2
 #import <React/RCTRootView.h>
3
 #import "UIImage+tint.h"
3
 #import "UIImage+tint.h"
4
+#import "UINavigationBar+utils.h"
4
 #import "RNNBottomTabOptions.h"
5
 #import "RNNBottomTabOptions.h"
5
 #import "RNNNavigationOptions.h"
6
 #import "RNNNavigationOptions.h"
6
 #import "RNNBackButtonOptions.h"
7
 #import "RNNBackButtonOptions.h"
160
 	}
161
 	}
161
 }
162
 }
162
 
163
 
163
-- (void)setBackButtonIcon:(UIImage *)icon withColor:(UIColor *)color title:(NSString *)title {
164
-	UIBarButtonItem *backItem = [[UIBarButtonItem alloc] init];
165
-	if (icon) {
166
-		backItem.image = color
167
-		? [[icon withTintColor:color] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]
168
-		: icon;
169
-
170
-		[self.navigationController.navigationBar setBackIndicatorImage:[UIImage new]];
171
-		[self.navigationController.navigationBar setBackIndicatorTransitionMaskImage:[UIImage new]];
172
-	}
173
-
174
-	UIViewController *lastViewControllerInStack = self.navigationController.viewControllers.count > 1 ? self.navigationController.viewControllers[self.navigationController.viewControllers.count - 2] : self.navigationController.topViewController;
175
-
176
-	backItem.title = title ? title : lastViewControllerInStack.navigationItem.title;
177
-	backItem.tintColor = color;
178
-
179
-	lastViewControllerInStack.navigationItem.backBarButtonItem = backItem;
180
-}
181
-
182
 - (void)applyBackButton:(RNNBackButtonOptions *)backButton {
164
 - (void)applyBackButton:(RNNBackButtonOptions *)backButton {
183
 	UIBarButtonItem *backItem = [UIBarButtonItem new];
165
 	UIBarButtonItem *backItem = [UIBarButtonItem new];
184
 	if (backButton.icon.hasValue) {
166
 	if (backButton.icon.hasValue) {

+ 0
- 31
playground/ios/NavigationTests/RNNComponentPresenterTest.m View File

173
 	XCTAssertEqual(self.uut.boundComponentId, @"componentId");
173
 	XCTAssertEqual(self.uut.boundComponentId, @"componentId");
174
 }
174
 }
175
 
175
 
176
-- (void)testApplyOptionsOnWillMoveToParent_shouldSetBackButtonOnBoundViewController_withTitle {
177
-	Text* title = [[Text alloc] initWithValue:@"Title"];
178
-	self.options.topBar.backButton.title = title;
179
-	[[(id) self.boundViewController expect] setBackButtonIcon:nil withColor:nil title:title.get];
180
-	[self.uut applyOptionsOnWillMoveToParentViewController:self.options];
181
-	[(id)self.boundViewController verify];
182
-}
183
-
184
-- (void)testApplyOptionsOnWillMoveToParent_shouldSetBackButtonOnBoundViewController_withHideTitle {
185
-	Text* title = [[Text alloc] initWithValue:@"Title"];
186
-	self.options.topBar.backButton.title = title;
187
-	self.options.topBar.backButton.showTitle = [[Bool alloc] initWithValue:@(0)];
188
-	[[(id) self.boundViewController expect] setBackButtonIcon:nil withColor:nil title:@""];
189
-	[self.uut applyOptionsOnWillMoveToParentViewController:self.options];
190
-	[(id)self.boundViewController verify];
191
-}
192
-
193
-- (void)testApplyOptionsOnWillMoveToParent_shouldSetBackButtonOnBoundViewController_withIcon {
194
-	Image* image = [[Image alloc] initWithValue:[UIImage new]];
195
-	self.options.topBar.backButton.icon = image;
196
-	[[(id) self.boundViewController expect] setBackButtonIcon:image.get withColor:nil title:nil];
197
-	[self.uut applyOptionsOnWillMoveToParentViewController:self.options];
198
-	[(id)self.boundViewController verify];
199
-}
200
-
201
-- (void)testApplyOptionsOnWillMoveToParent_shouldSetBackButtonOnBoundViewController_withDefaultValues {
202
-	[[(id) self.boundViewController expect] setBackButtonIcon:nil withColor:nil title:nil];
203
-	[self.uut applyOptionsOnWillMoveToParentViewController:self.options];
204
-	[(id)self.boundViewController verify];
205
-}
206
-
207
 - (void)testRemoveTitleComponentIfNeeded_componentIsRemovedIfTitleTextIsDefined {
176
 - (void)testRemoveTitleComponentIfNeeded_componentIsRemovedIfTitleTextIsDefined {
208
 	id mockTitle = [OCMockObject niceMockForClass:[RNNReactView class]];
177
 	id mockTitle = [OCMockObject niceMockForClass:[RNNReactView class]];
209
     OCMStub([self.componentRegistry createComponentIfNotExists:[OCMArg any] parentComponentId:[OCMArg any] reactViewReadyBlock:nil]).andReturn(mockTitle);
178
     OCMStub([self.componentRegistry createComponentIfNotExists:[OCMArg any] parentComponentId:[OCMArg any] reactViewReadyBlock:nil]).andReturn(mockTitle);

+ 31
- 0
playground/ios/NavigationTests/RNNStackPresenterTest.m View File

57
 	XCTAssertFalse([[self.uut.boundViewController navigationBar] prefersLargeTitles]);
57
 	XCTAssertFalse([[self.uut.boundViewController navigationBar] prefersLargeTitles]);
58
 }
58
 }
59
 
59
 
60
+- (void)testApplyOptions_shouldSetBackButtonOnBoundViewController_withTitle {
61
+	Text* title = [[Text alloc] initWithValue:@"Title"];
62
+	self.options.topBar.backButton.title = title;
63
+	[[_boundViewController expect] setBackButtonIcon:nil withColor:nil title:title.get showTitle:YES];
64
+	[self.uut applyOptions:self.options];
65
+	[_boundViewController verify];
66
+}
67
+
68
+- (void)testApplyOptions_shouldSetBackButtonOnBoundViewController_withHideTitle {
69
+	Text* title = [[Text alloc] initWithValue:@"Title"];
70
+	self.options.topBar.backButton.title = title;
71
+	self.options.topBar.backButton.showTitle = [[Bool alloc] initWithValue:@(0)];
72
+	[[(id) self.boundViewController expect] setBackButtonIcon:nil withColor:nil title:title.get showTitle:self.options.topBar.backButton.showTitle.get];
73
+	[self.uut applyOptions:self.options];
74
+	[(id)self.boundViewController verify];
75
+}
76
+
77
+- (void)testApplyOptions_shouldSetBackButtonOnBoundViewController_withIcon {
78
+	Image* image = [[Image alloc] initWithValue:[UIImage new]];
79
+	self.options.topBar.backButton.icon = image;
80
+	[[(id) self.boundViewController expect] setBackButtonIcon:image.get withColor:nil title:nil showTitle:YES];
81
+	[self.uut applyOptions:self.options];
82
+	[(id)self.boundViewController verify];
83
+}
84
+
85
+- (void)testApplyOptions_shouldSetBackButtonOnBoundViewController_withDefaultValues {
86
+	[[(id) self.boundViewController expect] setBackButtonIcon:nil withColor:nil title:nil showTitle:YES];
87
+	[self.uut applyOptions:self.options];
88
+	[(id)self.boundViewController verify];
89
+}
90
+
60
 @end
91
 @end

+ 38
- 0
playground/ios/NavigationTests/UINavigationController+RNNOptionsTest.m View File

11
     [super setUp];
11
     [super setUp];
12
 }
12
 }
13
 
13
 
14
+- (void)testSetBackButtonIcon_withColor_shouldSetColor {
15
+	UIViewController* vc = [UIViewController new];
16
+	UINavigationController* uut = [[UINavigationController alloc] initWithRootViewController:vc];
17
+	UIColor* color = [UIColor blackColor];
18
+
19
+	[uut setBackButtonIcon:nil withColor:color title:nil showTitle:nil];
20
+	XCTAssertEqual(color, vc.navigationItem.backBarButtonItem.tintColor);
21
+}
22
+
23
+- (void)testSetBackButtonIcon_withColor_shouldSetTitle {
24
+	UIViewController* vc = [UIViewController new];
25
+	UINavigationController* uut = [[UINavigationController alloc] initWithRootViewController:vc];
26
+    NSString* title = @"Title";
27
+
28
+    [uut setBackButtonIcon:nil withColor:nil title:title showTitle:YES];
29
+	XCTAssertEqual(title, vc.navigationItem.backBarButtonItem.title);
30
+}
31
+
32
+//- (void)testSetBackButtonIcon_withColor_shouldSetIcon {
33
+//	UIViewController* vc = [UIViewController new];
34
+//	UINavigationController* uut = [[UINavigationController alloc] initWithRootViewController:vc];
35
+//    UIImage* icon = [UIImage new];
36
+//
37
+//    [uut setBackButtonIcon:icon withColor:nil title:nil showTitle:nil];
38
+//	XCTAssertEqual(icon, vc.navigationItem.backBarButtonItem.image);
39
+//}
40
+
41
+- (void)testSetBackButtonIcon_shouldSetTitleOnPreviousViewControllerIfExists {
42
+	UIViewController* viewController1 = [UIViewController new];
43
+	UIViewController* viewController2 = [UIViewController new];
44
+	UINavigationController* uut = [[UINavigationController alloc] init];
45
+	[uut setViewControllers:@[viewController1, viewController2]];
46
+	NSString* title = @"Title";
47
+
48
+	[uut setBackButtonIcon:nil withColor:nil title:title showTitle:YES];
49
+	XCTAssertEqual(title, viewController1.navigationItem.backBarButtonItem.title);
50
+}
51
+
14
 @end
52
 @end

+ 0
- 38
playground/ios/NavigationTests/UIViewController+LayoutProtocolTest.m View File

42
 	XCTAssertEqual(uut.viewControllers[1], child2);
42
 	XCTAssertEqual(uut.viewControllers[1], child2);
43
 }
43
 }
44
 
44
 
45
-- (void)testSetBackButtonIcon_withColor_shouldSetColor {
46
-	UIViewController* uut = [UIViewController new];
47
-	[[UINavigationController alloc] initWithRootViewController:uut];
48
-	UIColor* color = [UIColor blackColor];
49
-
50
-    [uut setBackButtonIcon:nil withColor:color title:nil];
51
-	XCTAssertEqual(color, uut.navigationItem.backBarButtonItem.tintColor);
52
-}
53
-
54
-- (void)testSetBackButtonIcon_withColor_shouldSetTitle {
55
-	UIViewController* uut = [UIViewController new];
56
-    UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:uut];
57
-    NSString* title = @"Title";
58
-
59
-    [uut setBackButtonIcon:nil withColor:nil title:title];
60
-	XCTAssertEqual(title, uut.navigationItem.backBarButtonItem.title);
61
-}
62
-
63
-- (void)testSetBackButtonIcon_withColor_shouldSetIcon {
64
-	UIViewController* uut = [UIViewController new];
65
-    UINavigationController* nav = [[UINavigationController alloc] initWithRootViewController:uut];
66
-    UIImage* icon = [UIImage new];
67
-
68
-    [uut setBackButtonIcon:icon withColor:nil title:nil];
69
-	XCTAssertEqual(icon, uut.navigationItem.backBarButtonItem.image);
70
-}
71
-
72
-- (void)testSetBackButtonIcon_shouldSetTitleOnPreviousViewControllerIfExists {
73
-	UIViewController* uut = [UIViewController new];
74
-	UIViewController* viewController2 = [UIViewController new];
75
-	UINavigationController* nav = [[UINavigationController alloc] init];
76
-	[nav setViewControllers:@[uut, viewController2]];
77
-	NSString* title = @"Title";
78
-
79
-    [uut setBackButtonIcon:nil withColor:nil title:title];
80
-	XCTAssertEqual(title, uut.navigationItem.backBarButtonItem.title);
81
-}
82
-
83
 - (void)testResolveOptions {
45
 - (void)testResolveOptions {
84
 	RNNComponentPresenter* presenter = [[RNNComponentPresenter alloc] init];
46
 	RNNComponentPresenter* presenter = [[RNNComponentPresenter alloc] init];
85
 
47