Browse Source

handle hiding/showing the navigation bar properly when moving between screen that have a transparent navigation bar and ones that have visible bars. (#609)

Artal Druk 7 years ago
parent
commit
b6d196ddc0
1 changed files with 137 additions and 121 deletions
  1. 137
    121
      ios/RCCViewController.m

+ 137
- 121
ios/RCCViewController.m View File

@@ -96,60 +96,60 @@ const NSInteger TRANSPARENT_NAVBAR_TAG = 78264803;
96 96
 
97 97
 - (instancetype)initWithProps:(NSDictionary *)props children:(NSArray *)children globalProps:(NSDictionary *)globalProps bridge:(RCTBridge *)bridge
98 98
 {
99
-  NSString *component = props[@"component"];
100
-  if (!component) return nil;
101
-
102
-  NSDictionary *passProps = props[@"passProps"];
103
-  NSDictionary *navigatorStyle = props[@"style"];
104
-
105
-  NSMutableDictionary *mergedProps = [NSMutableDictionary dictionaryWithDictionary:globalProps];
106
-  [mergedProps addEntriesFromDictionary:passProps];
107
-  
108
-  RCTRootView *reactView = [[RCTRootView alloc] initWithBridge:bridge moduleName:component initialProperties:mergedProps];
109
-  if (!reactView) return nil;
110
-
111
-  self = [super init];
112
-  if (!self) return nil;
113
-
114
-  [self commonInit:reactView navigatorStyle:navigatorStyle props:props];
115
-
116
-  return self;
99
+    NSString *component = props[@"component"];
100
+    if (!component) return nil;
101
+    
102
+    NSDictionary *passProps = props[@"passProps"];
103
+    NSDictionary *navigatorStyle = props[@"style"];
104
+    
105
+    NSMutableDictionary *mergedProps = [NSMutableDictionary dictionaryWithDictionary:globalProps];
106
+    [mergedProps addEntriesFromDictionary:passProps];
107
+    
108
+    RCTRootView *reactView = [[RCTRootView alloc] initWithBridge:bridge moduleName:component initialProperties:mergedProps];
109
+    if (!reactView) return nil;
110
+    
111
+    self = [super init];
112
+    if (!self) return nil;
113
+    
114
+    [self commonInit:reactView navigatorStyle:navigatorStyle props:props];
115
+    
116
+    return self;
117 117
 }
118 118
 
119 119
 - (instancetype)initWithComponent:(NSString *)component passProps:(NSDictionary *)passProps navigatorStyle:(NSDictionary*)navigatorStyle globalProps:(NSDictionary *)globalProps bridge:(RCTBridge *)bridge
120 120
 {
121
-  NSMutableDictionary *mergedProps = [NSMutableDictionary dictionaryWithDictionary:globalProps];
122
-  [mergedProps addEntriesFromDictionary:passProps];
123
-  
124
-  RCTRootView *reactView = [[RCTRootView alloc] initWithBridge:bridge moduleName:component initialProperties:mergedProps];
125
-  if (!reactView) return nil;
126
-
127
-  self = [super init];
128
-  if (!self) return nil;
129
-
130
-  [self commonInit:reactView navigatorStyle:navigatorStyle props:passProps];
131
-
132
-  return self;
121
+    NSMutableDictionary *mergedProps = [NSMutableDictionary dictionaryWithDictionary:globalProps];
122
+    [mergedProps addEntriesFromDictionary:passProps];
123
+    
124
+    RCTRootView *reactView = [[RCTRootView alloc] initWithBridge:bridge moduleName:component initialProperties:mergedProps];
125
+    if (!reactView) return nil;
126
+    
127
+    self = [super init];
128
+    if (!self) return nil;
129
+    
130
+    [self commonInit:reactView navigatorStyle:navigatorStyle props:passProps];
131
+    
132
+    return self;
133 133
 }
134 134
 
135 135
 - (void)commonInit:(RCTRootView*)reactView navigatorStyle:(NSDictionary*)navigatorStyle props:(NSDictionary*)props
136 136
 {
137
-  self.view = reactView;
138
-  
139
-  self.edgesForExtendedLayout = UIRectEdgeNone; // default
140
-  self.automaticallyAdjustsScrollViewInsets = NO; // default
141
-  
142
-  self.navigatorStyle = [NSMutableDictionary dictionaryWithDictionary:navigatorStyle];
143
-  
144
-  [self setStyleOnInit];
145
-  
146
-  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onRNReload) name:RCTReloadNotification object:nil];
147
-  [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onCancelReactTouches) name:RCCViewControllerCancelReactTouchesNotification object:nil];
148
-  
149
-  // In order to support 3rd party native ViewControllers, we support passing a class name as a prop mamed `ExternalNativeScreenClass`
150
-  // In this case, we create an instance and add it as a child ViewController which preserves the VC lifecycle.
151
-  // In case some props are necessary in the native ViewController, the ExternalNativeScreenProps can be used to pass them
152
-  [self addExternalVCIfNecessary:props];
137
+    self.view = reactView;
138
+    
139
+    self.edgesForExtendedLayout = UIRectEdgeNone; // default
140
+    self.automaticallyAdjustsScrollViewInsets = NO; // default
141
+    
142
+    self.navigatorStyle = [NSMutableDictionary dictionaryWithDictionary:navigatorStyle];
143
+    
144
+    [self setStyleOnInit];
145
+    
146
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onRNReload) name:RCTReloadNotification object:nil];
147
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onCancelReactTouches) name:RCCViewControllerCancelReactTouchesNotification object:nil];
148
+    
149
+    // In order to support 3rd party native ViewControllers, we support passing a class name as a prop mamed `ExternalNativeScreenClass`
150
+    // In this case, we create an instance and add it as a child ViewController which preserves the VC lifecycle.
151
+    // In case some props are necessary in the native ViewController, the ExternalNativeScreenProps can be used to pass them
152
+    [self addExternalVCIfNecessary:props];
153 153
 }
154 154
 
155 155
 - (void)dealloc
@@ -166,9 +166,9 @@ const NSInteger TRANSPARENT_NAVBAR_TAG = 78264803;
166 166
 
167 167
 -(void)onCancelReactTouches
168 168
 {
169
-  if ([self.view isKindOfClass:[RCTRootView class]]){
170
-    [(RCTRootView*)self.view cancelTouches];
171
-  }
169
+    if ([self.view isKindOfClass:[RCTRootView class]]){
170
+        [(RCTRootView*)self.view cancelTouches];
171
+    }
172 172
 }
173 173
 
174 174
 - (void)viewWillAppear:(BOOL)animated
@@ -189,7 +189,7 @@ const NSInteger TRANSPARENT_NAVBAR_TAG = 78264803;
189 189
 // we want to reset the style to what we expect (so we need to reset on every willAppear)
190 190
 - (void)setStyleOnAppear
191 191
 {
192
-  [self setStyleOnAppearForViewController:self];
192
+    [self setStyleOnAppearForViewController:self];
193 193
 }
194 194
 
195 195
 -(void)setStyleOnAppearForViewController:(UIViewController*)viewController
@@ -200,7 +200,7 @@ const NSInteger TRANSPARENT_NAVBAR_TAG = 78264803;
200 200
         UIColor *color = screenBackgroundColor != (id)[NSNull null] ? [RCTConvert UIColor:screenBackgroundColor] : nil;
201 201
         self.view.backgroundColor = color;
202 202
     }
203
- 
203
+    
204 204
     NSString *navBarBackgroundColor = self.navigatorStyle[@"navBarBackgroundColor"];
205 205
     if (navBarBackgroundColor)
206 206
     {
@@ -323,29 +323,44 @@ const NSInteger TRANSPARENT_NAVBAR_TAG = 78264803;
323 323
     
324 324
     NSNumber *navBarTransparent = self.navigatorStyle[@"navBarTransparent"];
325 325
     BOOL navBarTransparentBool = navBarTransparent ? [navBarTransparent boolValue] : NO;
326
-    if (navBarTransparentBool)
327
-    {
328
-        if (![viewController.navigationController.navigationBar viewWithTag:TRANSPARENT_NAVBAR_TAG])
326
+    
327
+    void (^action)() = ^ {
328
+        if (navBarTransparentBool)
329 329
         {
330
-            [self storeOriginalNavBarImages];
331
-            
332
-            [viewController.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
333
-            viewController.navigationController.navigationBar.shadowImage = [UIImage new];
334
-            UIView *transparentView = [[UIView alloc] initWithFrame:CGRectZero];
335
-            transparentView.tag = TRANSPARENT_NAVBAR_TAG;
336
-            [viewController.navigationController.navigationBar insertSubview:transparentView atIndex:0];
330
+            if (![viewController.navigationController.navigationBar viewWithTag:TRANSPARENT_NAVBAR_TAG])
331
+            {
332
+                [self storeOriginalNavBarImages];
333
+                
334
+                [viewController.navigationController.navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
335
+                viewController.navigationController.navigationBar.shadowImage = [UIImage new];
336
+                UIView *transparentView = [[UIView alloc] initWithFrame:CGRectZero];
337
+                transparentView.tag = TRANSPARENT_NAVBAR_TAG;
338
+                [viewController.navigationController.navigationBar insertSubview:transparentView atIndex:0];
339
+            }
337 340
         }
338
-    }
339
-    else
340
-    {
341
-        UIView *transparentView = [viewController.navigationController.navigationBar viewWithTag:TRANSPARENT_NAVBAR_TAG];
342
-        if (transparentView)
341
+        else
343 342
         {
344
-            [transparentView removeFromSuperview];
345
-            [viewController.navigationController.navigationBar setBackgroundImage:self.originalNavBarImages[@"bgImage"] forBarMetrics:UIBarMetricsDefault];
346
-            viewController.navigationController.navigationBar.shadowImage = self.originalNavBarImages[@"shadowImage"];
347
-            self.originalNavBarImages = nil;
343
+            UIView *transparentView = [viewController.navigationController.navigationBar viewWithTag:TRANSPARENT_NAVBAR_TAG];
344
+            if (transparentView)
345
+            {
346
+                [transparentView removeFromSuperview];
347
+                [viewController.navigationController.navigationBar setBackgroundImage:self.originalNavBarImages[@"bgImage"] forBarMetrics:UIBarMetricsDefault];
348
+                viewController.navigationController.navigationBar.shadowImage = self.originalNavBarImages[@"shadowImage"];
349
+                self.originalNavBarImages = nil;
350
+            }
348 351
         }
352
+    };
353
+    
354
+    if(self.transitionCoordinator.initiallyInteractive || !navBarTransparentBool) {
355
+        action();
356
+    } else {
357
+        UIView* backgroundView = [self.navigationController.navigationBar valueForKey:@"backgroundView"];
358
+        CGFloat originalAlpha = backgroundView.alpha;
359
+        backgroundView.alpha = navBarTransparentBool ? 0.0 : 1.0;
360
+        [self.transitionCoordinator animateAlongsideTransition:nil completion:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
361
+            action();
362
+            backgroundView.alpha = originalAlpha;
363
+        }];
349 364
     }
350 365
     
351 366
     NSNumber *navBarTranslucent = self.navigatorStyle[@"navBarTranslucent"];
@@ -391,18 +406,18 @@ const NSInteger TRANSPARENT_NAVBAR_TAG = 78264803;
391 406
     {
392 407
         self.navBarHairlineImageView.hidden = NO;
393 408
     }
394
-  
409
+    
395 410
     //Bug fix: in case there is a interactivePopGestureRecognizer, it prevents react-native from getting touch events on the left screen area that the gesture handles
396 411
     //overriding the delegate of the gesture prevents this from happening while keeping the gesture intact (another option was to disable it completely by demand)
397 412
     self.originalInteractivePopGestureDelegate = nil;
398 413
     if (self.navigationController != nil && self.navigationController.interactivePopGestureRecognizer != nil)
399 414
     {
400
-      id <UIGestureRecognizerDelegate> interactivePopGestureRecognizer = self.navigationController.interactivePopGestureRecognizer.delegate;
401
-      if (interactivePopGestureRecognizer != nil)
402
-      {
403
-        self.originalInteractivePopGestureDelegate = interactivePopGestureRecognizer;
404
-        self.navigationController.interactivePopGestureRecognizer.delegate = self;
405
-      }
415
+        id <UIGestureRecognizerDelegate> interactivePopGestureRecognizer = self.navigationController.interactivePopGestureRecognizer.delegate;
416
+        if (interactivePopGestureRecognizer != nil)
417
+        {
418
+            self.originalInteractivePopGestureDelegate = interactivePopGestureRecognizer;
419
+            self.navigationController.interactivePopGestureRecognizer.delegate = self;
420
+        }
406 421
     }
407 422
 }
408 423
 
@@ -425,11 +440,11 @@ const NSInteger TRANSPARENT_NAVBAR_TAG = 78264803;
425 440
 -(void)setStyleOnDisappear
426 441
 {
427 442
     self.navBarHairlineImageView.hidden = NO;
428
-  
443
+    
429 444
     if (self.navigationController != nil && self.navigationController.interactivePopGestureRecognizer != nil && self.originalInteractivePopGestureDelegate != nil)
430 445
     {
431
-      self.navigationController.interactivePopGestureRecognizer.delegate = self.originalInteractivePopGestureDelegate;
432
-      self.originalInteractivePopGestureDelegate = nil;
446
+        self.navigationController.interactivePopGestureRecognizer.delegate = self.originalInteractivePopGestureDelegate;
447
+        self.originalInteractivePopGestureDelegate = nil;
433 448
     }
434 449
 }
435 450
 
@@ -524,57 +539,58 @@ const NSInteger TRANSPARENT_NAVBAR_TAG = 78264803;
524 539
 
525 540
 -(void)addExternalVCIfNecessary:(NSDictionary*)props
526 541
 {
527
-  NSString *externalScreenClass = props[@"externalNativeScreenClass"];
528
-  if (externalScreenClass != nil)
529
-  {
530
-    Class class = NSClassFromString(externalScreenClass);
531
-    if (class != NULL)
532
-    {
533
-      id obj = [[class alloc] init];
534
-      if (obj != nil && [obj isKindOfClass:[UIViewController class]] && [obj conformsToProtocol:@protocol(RCCExternalViewControllerProtocol)])
535
-      {
536
-        ((id <RCCExternalViewControllerProtocol>)obj).controllerDelegate = self;
537
-        [obj setProps:props[@"externalNativeScreenProps"]];
538
-        
539
-        UIViewController *viewController = (UIViewController*)obj;
540
-        [self addChildViewController:viewController];
541
-        viewController.view.frame = self.view.bounds;
542
-        [self.view addSubview:viewController.view];
543
-        [viewController didMoveToParentViewController:self];
544
-      }
545
-      else
546
-      {
547
-        NSLog(@"addExternalVCIfNecessary: could not create instance. Make sure that your class is a UIViewController whihc confirms to RCCExternalViewControllerProtocol");
548
-      }
549
-    }
550
-    else
542
+    NSString *externalScreenClass = props[@"externalNativeScreenClass"];
543
+    if (externalScreenClass != nil)
551 544
     {
552
-      NSLog(@"addExternalVCIfNecessary: could not create class from string. Check that the proper class name wass passed in ExternalNativeScreenClass");
545
+        Class class = NSClassFromString(externalScreenClass);
546
+        if (class != NULL)
547
+        {
548
+            id obj = [[class alloc] init];
549
+            if (obj != nil && [obj isKindOfClass:[UIViewController class]] && [obj conformsToProtocol:@protocol(RCCExternalViewControllerProtocol)])
550
+            {
551
+                ((id <RCCExternalViewControllerProtocol>)obj).controllerDelegate = self;
552
+                [obj setProps:props[@"externalNativeScreenProps"]];
553
+                
554
+                UIViewController *viewController = (UIViewController*)obj;
555
+                [self addChildViewController:viewController];
556
+                viewController.view.frame = self.view.bounds;
557
+                [self.view addSubview:viewController.view];
558
+                [viewController didMoveToParentViewController:self];
559
+            }
560
+            else
561
+            {
562
+                NSLog(@"addExternalVCIfNecessary: could not create instance. Make sure that your class is a UIViewController whihc confirms to RCCExternalViewControllerProtocol");
563
+            }
564
+        }
565
+        else
566
+        {
567
+            NSLog(@"addExternalVCIfNecessary: could not create class from string. Check that the proper class name wass passed in ExternalNativeScreenClass");
568
+        }
553 569
     }
554
-  }
555 570
 }
556 571
 
557 572
 #pragma mark - NewRelic
558 573
 
559 574
 - (NSString*) customNewRelicInteractionName
560 575
 {
561
-  NSString *interactionName = nil;
562
-  
563
-  if (self.view != nil && [self.view isKindOfClass:[RCTRootView class]])
564
-  {
565
-    NSString *moduleName = ((RCTRootView*)self.view).moduleName;
566
-    if(moduleName != nil)
576
+    NSString *interactionName = nil;
577
+    
578
+    if (self.view != nil && [self.view isKindOfClass:[RCTRootView class]])
567 579
     {
568
-      interactionName = [NSString stringWithFormat:@"RCCViewController: %@", moduleName];
580
+        NSString *moduleName = ((RCTRootView*)self.view).moduleName;
581
+        if(moduleName != nil)
582
+        {
583
+            interactionName = [NSString stringWithFormat:@"RCCViewController: %@", moduleName];
584
+        }
569 585
     }
570
-  }
571
-  
572
-  if (interactionName == nil)
573
-  {
574
-    interactionName = [NSString stringWithFormat:@"RCCViewController with title: %@", self.title];
575
-  }
576
-  
577
-  return interactionName;
586
+    
587
+    if (interactionName == nil)
588
+    {
589
+        interactionName = [NSString stringWithFormat:@"RCCViewController with title: %@", self.title];
590
+    }
591
+    
592
+    return interactionName;
578 593
 }
579 594
 
595
+
580 596
 @end