Parcourir la source

Support a “modal” prop for tabbed iOS apps (#1578)

* feat: support a “modal” prop for tabbed ios apps

* fix: apply temp fix for react-native-navigation#1502 (#1)

* fix: enable fab icon scaling (#2)

* v1.1.340 [ci skip]

* Update FloatingActionButtonCoordinator.java

* Update top-level-api.md

* Update package.json
Kevin Barrett il y a 6 ans
Parent
révision
5cd2972ca0
2 fichiers modifiés avec 164 ajouts et 81 suppressions
  1. 2
    1
      docs/top-level-api.md
  2. 162
    80
      ios/RCCTabBarController.m

+ 2
- 1
docs/top-level-api.md Voir le fichier

@@ -44,7 +44,8 @@ Navigation.startTabBasedApp({
44 44
       title: 'Screen One', // title of the screen as appears in the nav bar (optional)
45 45
       titleImage: require('../img/titleImage.png'), // iOS only. navigation bar title image instead of the title text of the pushed screen (optional)
46 46
       navigatorStyle: {}, // override the navigator style for the tab screen, see "Styling the navigator" below (optional),
47
-      navigatorButtons: {} // override the nav buttons for the tab screen, see "Adding buttons to the navigator" below (optional)
47
+      navigatorButtons: {}, // override the nav buttons for the tab screen, see "Adding buttons to the navigator" below (optional)
48
+      modal: false // Prevent tab selection and send a 'modalTabSelected' navigator event instead (optional, iOS only)
48 49
     },
49 50
     {
50 51
       label: 'Two',

+ 162
- 80
ios/RCCTabBarController.m Voir le fichier

@@ -14,6 +14,12 @@
14 14
 
15 15
 @end
16 16
 
17
+@interface RCCTabBarController ()
18
+
19
+@property (nonatomic, strong) NSSet *modalTabIndices;
20
+
21
+@end
22
+
17 23
 @implementation RCCTabBarController
18 24
 
19 25
 
@@ -22,37 +28,47 @@
22 28
 }
23 29
 
24 30
 - (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController {
25
-    id queue = [[RCCManager sharedInstance].getBridge uiManager].methodQueue;
26
-    dispatch_async(queue, ^{
27
-        [[[RCCManager sharedInstance].getBridge uiManager] configureNextLayoutAnimation:nil withCallback:^(NSArray* arr){} errorCallback:^(NSArray* arr){}];
28
-    });
29
-    
30
-    if (tabBarController.selectedIndex != [tabBarController.viewControllers indexOfObject:viewController]) {
31
-        NSDictionary *body = @{
32
-                               @"selectedTabIndex": @([tabBarController.viewControllers indexOfObject:viewController]),
33
-                               @"unselectedTabIndex": @(tabBarController.selectedIndex)
34
-                               };
35
-        [RCCTabBarController sendScreenTabChangedEvent:viewController body:body];
36
-        
37
-        [[[RCCManager sharedInstance] getBridge].eventDispatcher sendAppEventWithName:@"bottomTabSelected" body:body];
38
-        if ([viewController isKindOfClass:[UINavigationController class]]) {
39
-            UINavigationController *navigationController = (UINavigationController*)viewController;
40
-            UIViewController *topViewController = navigationController.topViewController;
41
-            
42
-            if ([topViewController isKindOfClass:[RCCViewController class]]) {
43
-                RCCViewController *topRCCViewController = (RCCViewController*)topViewController;
44
-                topRCCViewController.commandType = COMMAND_TYPE_BOTTOME_TAB_SELECTED;
45
-                topRCCViewController.timestamp = [RCTHelpers getTimestampString];
46
-            }
47
-        }
48
-        
49
-    } else {
50
-        [RCCTabBarController sendScreenTabPressedEvent:viewController body:nil];
31
+  id queue = [[RCCManager sharedInstance].getBridge uiManager].methodQueue;
32
+  dispatch_async(queue, ^{
33
+    [[[RCCManager sharedInstance].getBridge uiManager] configureNextLayoutAnimation:nil withCallback:^(NSArray* arr){} errorCallback:^(NSArray* arr){}];
34
+  });
35
+
36
+  NSUInteger selectedIndex = [tabBarController.viewControllers indexOfObject:viewController];
37
+  
38
+  if (tabBarController.selectedIndex != selectedIndex) {
39
+    NSDictionary *body = @{
40
+                           @"selectedTabIndex": @(selectedIndex),
41
+                           @"unselectedTabIndex": @(tabBarController.selectedIndex)
42
+                           };
43
+
44
+    if ([self.modalTabIndices containsObject:@(selectedIndex)]) {
45
+      [RCCTabBarController sendScreenTabModalEvent:viewController body:body];
46
+      return NO;
51 47
     }
52 48
     
53
-    
54
-    
55
-    return YES;
49
+    else {
50
+      [RCCTabBarController sendScreenTabChangedEvent:viewController body:body];
51
+
52
+      [[[RCCManager sharedInstance] getBridge].eventDispatcher sendAppEventWithName:@"bottomTabSelected" body:body];
53
+    }
54
+
55
+    if ([viewController isKindOfClass:[UINavigationController class]]) {
56
+      UINavigationController *navigationController = (UINavigationController*)viewController;
57
+      UIViewController *topViewController = navigationController.topViewController;
58
+
59
+      if ([topViewController isKindOfClass:[RCCViewController class]]) {
60
+        RCCViewController *topRCCViewController = (RCCViewController*)topViewController;
61
+        topRCCViewController.commandType = COMMAND_TYPE_BOTTOME_TAB_SELECTED;
62
+        topRCCViewController.timestamp = [RCTHelpers getTimestampString];
63
+      }
64
+    }
65
+  } else {
66
+    [RCCTabBarController sendScreenTabPressedEvent:viewController body:nil];
67
+  }
68
+  
69
+  
70
+  
71
+  return YES;
56 72
 }
57 73
 
58 74
 - (UIImage *)image:(UIImage*)image withColor:(UIColor *)color1 {
@@ -70,59 +86,105 @@
70 86
     return newImage;
71 87
 }
72 88
 
73
-- (instancetype)initWithProps:(NSDictionary *)props children:(NSArray *)children globalProps:(NSDictionary*)globalProps bridge:(RCTBridge *)bridge {
74
-    self = [super init];
75
-    if (!self) return nil;
89
+- (instancetype)initWithProps:(NSDictionary *)props children:(NSArray *)children globalProps:(NSDictionary*)globalProps bridge:(RCTBridge *)bridge
90
+{
91
+  self = [super init];
92
+  if (!self) return nil;
93
+  
94
+  self.delegate = self;
95
+  
96
+  self.tabBar.translucent = YES; // default
97
+  
98
+  UIColor *buttonColor = nil;
99
+  UIColor *selectedButtonColor = nil;
100
+  UIColor *labelColor = nil;
101
+  UIColor *selectedLabelColor = nil;
102
+  NSDictionary *tabsStyle = props[@"style"];
103
+  if (tabsStyle)
104
+  {
105
+    NSString *tabBarButtonColor = tabsStyle[@"tabBarButtonColor"];
106
+    if (tabBarButtonColor)
107
+    {
108
+      UIColor *color = tabBarButtonColor != (id)[NSNull null] ? [RCTConvert UIColor:tabBarButtonColor] : nil;
109
+      self.tabBar.tintColor = color;
110
+      buttonColor = color;
111
+      selectedButtonColor = color;
112
+    }
113
+    NSString *tabBarSelectedButtonColor = tabsStyle[@"tabBarSelectedButtonColor"];
114
+    if (tabBarSelectedButtonColor)
115
+    {
116
+      UIColor *color = tabBarSelectedButtonColor != (id)[NSNull null] ? [RCTConvert UIColor:tabBarSelectedButtonColor] : nil;
117
+      self.tabBar.tintColor = color;
118
+      selectedButtonColor = color;
119
+    }
120
+    NSString *tabBarLabelColor = tabsStyle[@"tabBarLabelColor"];
121
+    if(tabBarLabelColor) {
122
+      UIColor *color = tabBarLabelColor != (id)[NSNull null] ? [RCTConvert UIColor:tabBarLabelColor] : nil;
123
+      labelColor = color;
124
+    }
125
+    NSString *tabBarSelectedLabelColor = tabsStyle[@"tabBarSelectedLabelColor"];
126
+    if(tabBarLabelColor) {
127
+      UIColor *color = tabBarSelectedLabelColor != (id)[NSNull null] ? [RCTConvert UIColor:
128
+                                                                        tabBarSelectedLabelColor] : nil;
129
+      selectedLabelColor = color;
130
+    }
131
+    NSString *tabBarBackgroundColor = tabsStyle[@"tabBarBackgroundColor"];
132
+    if (tabBarBackgroundColor)
133
+    {
134
+      UIColor *color = tabBarBackgroundColor != (id)[NSNull null] ? [RCTConvert UIColor:tabBarBackgroundColor] : nil;
135
+      self.tabBar.barTintColor = color;
136
+    }
137
+
138
+    NSString *tabBarTranslucent = tabsStyle[@"tabBarTranslucent"];
139
+    if (tabBarTranslucent)
140
+    {
141
+      self.tabBar.translucent = [tabBarTranslucent boolValue] ? YES : NO;
142
+    }
143
+
144
+    NSString *tabBarHideShadow = tabsStyle[@"tabBarHideShadow"];
145
+    if (tabBarHideShadow)
146
+    {
147
+      self.tabBar.clipsToBounds = [tabBarHideShadow boolValue] ? YES : NO;
148
+    }
149
+  }
150
+  
151
+  NSMutableArray *viewControllers = [NSMutableArray array];
152
+  NSMutableSet *modalTabs = [NSMutableSet new];
153
+  
154
+  // go over all the tab bar items
155
+  for (NSDictionary *tabItemLayout in children)
156
+  {
157
+    // make sure the layout is valid
158
+    if (![tabItemLayout[@"type"] isEqualToString:@"TabBarControllerIOS.Item"]) continue;
159
+    if (!tabItemLayout[@"props"]) continue;
76 160
     
77 161
     self.delegate = self;
78 162
     
79
-    self.tabBar.translucent = YES; // default
80
-    
81
-    UIColor *buttonColor = nil;
82
-    UIColor *selectedButtonColor = nil;
83
-    UIColor *labelColor = nil;
84
-    UIColor *selectedLabelColor = nil;
85
-    NSDictionary *tabsStyle = props[@"style"];
86
-    if (tabsStyle) {
87
-        NSString *tabBarButtonColor = tabsStyle[@"tabBarButtonColor"];
88
-        if (tabBarButtonColor) {
89
-            UIColor *color = tabBarButtonColor != (id)[NSNull null] ? [RCTConvert UIColor:tabBarButtonColor] : nil;
90
-            self.tabBar.tintColor = color;
91
-            buttonColor = color;
92
-            selectedButtonColor = color;
93
-        }
94
-        NSString *tabBarSelectedButtonColor = tabsStyle[@"tabBarSelectedButtonColor"];
95
-        if (tabBarSelectedButtonColor) {
96
-            UIColor *color = tabBarSelectedButtonColor != (id)[NSNull null] ? [RCTConvert UIColor:tabBarSelectedButtonColor] : nil;
97
-            self.tabBar.tintColor = color;
98
-            selectedButtonColor = color;
99
-        }
100
-        NSString *tabBarLabelColor = tabsStyle[@"tabBarLabelColor"];
101
-        if (tabBarLabelColor) {
102
-            UIColor *color = tabBarLabelColor != (id)[NSNull null] ? [RCTConvert UIColor:tabBarLabelColor] : nil;
103
-            labelColor = color;
104
-        }
105
-        NSString *tabBarSelectedLabelColor = tabsStyle[@"tabBarSelectedLabelColor"];
106
-        if (tabBarLabelColor) {
107
-            UIColor *color = tabBarSelectedLabelColor != (id)[NSNull null] ? [RCTConvert UIColor:
108
-                                                                              tabBarSelectedLabelColor] : nil;
109
-            selectedLabelColor = color;
110
-        }
111
-        NSString *tabBarBackgroundColor = tabsStyle[@"tabBarBackgroundColor"];
112
-        if (tabBarBackgroundColor) {
113
-            UIColor *color = tabBarBackgroundColor != (id)[NSNull null] ? [RCTConvert UIColor:tabBarBackgroundColor] : nil;
114
-            self.tabBar.barTintColor = color;
115
-        }
116
-        
117
-        NSString *tabBarTranslucent = tabsStyle[@"tabBarTranslucent"];
118
-        if (tabBarTranslucent) {
119
-            self.tabBar.translucent = [tabBarTranslucent boolValue] ? YES : NO;
120
-        }
121
-        
122
-        NSString *tabBarHideShadow = tabsStyle[@"tabBarHideShadow"];
123
-        if (tabBarHideShadow) {
124
-            self.tabBar.clipsToBounds = [tabBarHideShadow boolValue] ? YES : NO;
125
-        }
163
+    // create the tab icon and title
164
+    NSString *title = tabItemLayout[@"props"][@"title"];
165
+    id isModal = tabItemLayout[@"props"][@"modal"];
166
+    if (isModal && isModal != (id)[NSNull null]) {
167
+      BOOL isModalBool = [RCTConvert BOOL:isModal];
168
+      if (isModalBool) {
169
+        [modalTabs addObject:@([viewControllers count])];
170
+      }
171
+    }
172
+    UIImage *iconImage = nil;
173
+    id icon = tabItemLayout[@"props"][@"icon"];
174
+    if (icon)
175
+    {
176
+      iconImage = [RCTConvert UIImage:icon];
177
+      if (buttonColor)
178
+      {
179
+        iconImage = [[self image:iconImage withColor:buttonColor] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
180
+      }
181
+    }
182
+    UIImage *iconImageSelected = nil;
183
+    id selectedIcon = tabItemLayout[@"props"][@"selectedIcon"];
184
+    if (selectedIcon) {
185
+      iconImageSelected = [RCTConvert UIImage:selectedIcon];
186
+    } else {
187
+      iconImageSelected = [RCTConvert UIImage:icon];
126 188
     }
127 189
     
128 190
     NSMutableArray *viewControllers = [NSMutableArray array];
@@ -212,7 +274,23 @@
212 274
     
213 275
     [self setRotation:props];
214 276
     
215
-    return self;
277
+    [viewControllers addObject:viewController];
278
+  }
279
+  
280
+  // replace the tabs
281
+  self.viewControllers = viewControllers;
282
+  self.modalTabIndices = [modalTabs copy];
283
+
284
+  NSNumber *initialTab = tabsStyle[@"initialTabIndex"];
285
+  if (initialTab)
286
+  {
287
+    NSInteger initialTabIndex = initialTab.integerValue;
288
+    [self setSelectedIndex:initialTabIndex];
289
+  }
290
+  
291
+  [self setRotation:props];
292
+  
293
+  return self;
216 294
 }
217 295
 
218 296
 - (void)performAction:(NSString*)performAction actionParams:(NSDictionary*)actionParams bridge:(RCTBridge *)bridge completion:(void (^)(void))completion {
@@ -347,6 +425,10 @@
347 425
     [RCCTabBarController sendTabEvent:@"bottomTabReselected" controller:viewController body:body];
348 426
 }
349 427
 
428
++(void)sendScreenTabModalEvent:(UIViewController*)viewController body:(NSDictionary*)body{
429
+  [RCCTabBarController sendTabEvent:@"modalTabSelected" controller:viewController body:body];
430
+}
431
+
350 432
 +(void)sendTabEvent:(NSString *)event controller:(UIViewController*)viewController body:(NSDictionary*)body{
351 433
     if ([viewController.view isKindOfClass:[RCTRootView class]]){
352 434
         RCTRootView *rootView = (RCTRootView *)viewController.view;