Browse Source

Re: Now allowing the custom nav bar to take up the whole space on iOS (#2620)

* Add support for react-native 0.52.0

* Refactore a bit

1. Rename `DevCommandsHandlerProxy` to `DevHelperProxy` so it reflects the changes in RN. See d19afc73f5 .
2. Add few comments to show which code is used on `RN >= 0.52` and which on `RN <= 0.51`.

* Now allowing the custom nav bar to take up the whole space on iOS

The custom nav bar on iOS was really just a custom view applied to the title of the navigation bar.
There were problems with this approach, because the navigation bar messes up the frame of the title very frequently, especially when the orientation is changing. That behaviour is accepted when the title is a label, but not when we have a custom component.

With this pull request the custom nav bar component can take up the full width of the navigation bar, no matter what orientation we're at.

* Added mix of native btns and custom component on the Custom TopBar screen of the example project
Ioannis Kokkinidis 6 years ago
parent
commit
93de04e13f

+ 6
- 5
example/src/screens/types/CustomTopBar.js View File

18
   render() {
18
   render() {
19
     return (
19
     return (
20
       <View style={styles.container}>
20
       <View style={styles.container}>
21
-        <TouchableOpacity stye={styles.button} onPress={ () => Alert.alert(this.props.title, 'Thanks for that :)') }>
22
-          <Text style={styles.text}>Press Me</Text>
21
+        <TouchableOpacity style={styles.button} onPress={ () => Alert.alert(this.props.title, 'Hello custom btn :)') }>
22
+          <Text style={styles.text}>Custom</Text>
23
         </TouchableOpacity>
23
         </TouchableOpacity>
24
       </View>
24
       </View>
25
     );
25
     );
30
   container: {
30
   container: {
31
     flex: 1,
31
     flex: 1,
32
     justifyContent: 'center',
32
     justifyContent: 'center',
33
-    alignItems: 'center'
33
+    alignItems: 'center',
34
+    // backgroundColor: 'yellow'
34
   },
35
   },
35
   button: {
36
   button: {
36
     alignSelf: 'center',
37
     alignSelf: 'center',
37
-    backgroundColor: 'green'
38
+    // backgroundColor: 'green'
38
   },
39
   },
39
   text: {
40
   text: {
40
     alignSelf: 'center',
41
     alignSelf: 'center',
41
-    color: Platform.OS === 'ios' ? 'black' : 'white'
42
+    color: 'white'
42
   }
43
   }
43
 });
44
 });
44
 
45
 

+ 31
- 1
example/src/screens/types/CustomTopBarScreen.js View File

10
 Navigation.registerComponent('example.CustomTopBar', () => CustomTopBar);
10
 Navigation.registerComponent('example.CustomTopBar', () => CustomTopBar);
11
 
11
 
12
 export default class CustomTopBarScreen extends Component {
12
 export default class CustomTopBarScreen extends Component {
13
+
14
+  static navigatorButtons = {
15
+    leftButtons: [
16
+      {
17
+        title: 'Back',
18
+        id: 'helloBtn',
19
+      }
20
+    ],
21
+    rightButtons: [
22
+      {
23
+        title: 'Right',
24
+        id: 'helloBtn2',
25
+      }
26
+    ],
27
+  };
28
+
13
   componentDidMount() {
29
   componentDidMount() {
14
     this.props.navigator.setStyle({
30
     this.props.navigator.setStyle({
15
       navBarCustomView: 'example.CustomTopBar',
31
       navBarCustomView: 'example.CustomTopBar',
16
       navBarComponentAlignment: 'center',
32
       navBarComponentAlignment: 'center',
17
-      navBarCustomViewInitialProps: {title: 'Hi Custom'}
33
+      navBarCustomViewInitialProps: {
34
+        title: 'Hi Custom',
35
+        navigator: this.props.navigator,
36
+      },
37
+    });
38
+    this.props.navigator.setOnNavigatorEvent((e) => {
39
+      if (e.type == 'NavBarButtonPress') { // this is the event type for button presses
40
+        if (e.id == 'helloBtn') { // this is the same id field from the static navigatorButtons definition
41
+          this.props.navigator.pop();
42
+          // alert('Hello left btn');
43
+        }
44
+        if (e.id == 'helloBtn2') { // this is the same id field from the static navigatorButtons definition
45
+          alert('Hello right btn');
46
+        }
47
+      }
18
     });
48
     });
19
   }
49
   }
20
 
50
 

+ 1
- 0
ios/RCCCustomTitleView.h View File

11
 @interface RCCCustomTitleView : UIView
11
 @interface RCCCustomTitleView : UIView
12
 
12
 
13
 -(instancetype)initWithFrame:(CGRect)frame subView:(UIView*)subView alignment:(NSString*)alignment;
13
 -(instancetype)initWithFrame:(CGRect)frame subView:(UIView*)subView alignment:(NSString*)alignment;
14
+- (void) viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator;
14
 
15
 
15
 @end
16
 @end

+ 54
- 0
ios/RCCCustomTitleView.m View File

11
 @interface RCCCustomTitleView ()
11
 @interface RCCCustomTitleView ()
12
 @property (nonatomic, strong) UIView *subView;
12
 @property (nonatomic, strong) UIView *subView;
13
 @property (nonatomic, strong) NSString *subViewAlign;
13
 @property (nonatomic, strong) NSString *subViewAlign;
14
+@property float initialWidth;
14
 @end
15
 @end
15
 
16
 
16
 @implementation RCCCustomTitleView
17
 @implementation RCCCustomTitleView
17
 
18
 
18
 
19
 
19
 -(instancetype)initWithFrame:(CGRect)frame subView:(UIView*)subView alignment:(NSString*)alignment {
20
 -(instancetype)initWithFrame:(CGRect)frame subView:(UIView*)subView alignment:(NSString*)alignment {
21
+    _initialWidth = frame.size.width;
20
     self = [super initWithFrame:frame];
22
     self = [super initWithFrame:frame];
21
     
23
     
22
     if (self) {
24
     if (self) {
52
     }
54
     }
53
 }
55
 }
54
 
56
 
57
+- (void)setFrame:(CGRect) frame {
58
+    float referenceWidth = [self statusBarWidth];
59
+    if (referenceWidth == 0) {
60
+        referenceWidth = _initialWidth;
61
+    }
62
+    float newNavBarWidth = frame.size.width;
63
+    BOOL frameNeedsToBeCorrected = newNavBarWidth < referenceWidth || CGRectEqualToRect(self.frame, CGRectZero);
64
+
65
+    if (frameNeedsToBeCorrected) {
66
+        // first we need to find out the total point diff of the status bar and the nav bar
67
+        float navBarHorizontalMargin = referenceWidth - newNavBarWidth;
68
+        
69
+        CGRect correctedFrame = frame;
70
+
71
+        // then we need to place the nav bar half times the horizontal margin to the left
72
+        correctedFrame.origin.x = -(navBarHorizontalMargin / 2);
73
+        
74
+        // and finally set the width so that it's equal to the status bar width
75
+        correctedFrame.size.width = referenceWidth;
76
+        
77
+        [super setFrame:correctedFrame];
78
+    } else if (frame.size.height != self.frame.size.height) { // otherwise
79
+        // if only the height has changed
80
+        CGRect newHeightFrame = self.frame;
81
+        // make sure we update just the height
82
+        newHeightFrame.size.height = frame.size.height;
83
+        [super setFrame:newHeightFrame];
84
+    }
85
+    
86
+    // keep a ref to the last frame, so that we avoid setting the frame twice for no reason
87
+//    _lastFrame = frame;
88
+}
89
+
90
+
91
+- (void) viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
92
+    // whenever the orientation changes this runs
93
+    // and sets the nav bar item width to the new size width
94
+    CGRect newFrame = self.frame;
95
+
96
+    if (newFrame.size.width < size.width) {
97
+        newFrame.size.width = size.width;
98
+        newFrame.origin.x = 0;
99
+    }
100
+    [super setFrame:newFrame];
101
+}
102
+
103
+-(float) statusBarWidth {
104
+    CGSize statusBarSize = [[UIApplication sharedApplication] statusBarFrame].size;
105
+    return MAX(statusBarSize.width, statusBarSize.height);
106
+}
107
+
108
+
55
 @end
109
 @end

+ 12
- 2
ios/RCCViewController.m View File

643
       NSDictionary *initialProps = self.navigatorStyle[@"navBarCustomViewInitialProps"];
643
       NSDictionary *initialProps = self.navigatorStyle[@"navBarCustomViewInitialProps"];
644
       RCTRootView *reactView = [[RCTRootView alloc] initWithBridge:bridge moduleName:navBarCustomView initialProperties:initialProps];
644
       RCTRootView *reactView = [[RCTRootView alloc] initWithBridge:bridge moduleName:navBarCustomView initialProperties:initialProps];
645
       
645
       
646
-      RCCCustomTitleView *titleView = [[RCCCustomTitleView alloc] initWithFrame:self.navigationController.navigationBar.bounds subView:reactView alignment:self.navigatorStyle[@"navBarComponentAlignment"]];
646
+      RCCCustomTitleView *titleView = [[RCCCustomTitleView alloc] initWithFrame:self.navigationController.navigationBar.bounds
647
+                                                                        subView:reactView
648
+                                                                      alignment:self.navigatorStyle[@"navBarComponentAlignment"]];
647
       titleView.backgroundColor = [UIColor clearColor];
649
       titleView.backgroundColor = [UIColor clearColor];
648
       reactView.backgroundColor = [UIColor clearColor];
650
       reactView.backgroundColor = [UIColor clearColor];
649
       
651
       
650
       self.navigationItem.titleView = titleView;
652
       self.navigationItem.titleView = titleView;
651
       
653
       
652
       self.navigationItem.titleView.backgroundColor = [UIColor clearColor];
654
       self.navigationItem.titleView.backgroundColor = [UIColor clearColor];
653
-      self.navigationItem.titleView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
655
+      self.navigationItem.titleView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
654
       self.navigationItem.titleView.clipsToBounds = YES;
656
       self.navigationItem.titleView.clipsToBounds = YES;
655
     }
657
     }
656
   }
658
   }
676
   #endif
678
   #endif
677
 }
679
 }
678
 
680
 
681
+- (void) viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
682
+  [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
683
+  RCCCustomTitleView* customNavBar = (RCCCustomTitleView*) self.navigationItem.titleView;
684
+  if (customNavBar && [customNavBar isKindOfClass:[RCCCustomTitleView class]]) {
685
+    [customNavBar viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
686
+  }
687
+}
688
+
679
 
689
 
680
 -(void)storeOriginalNavBarImages {
690
 -(void)storeOriginalNavBarImages {
681
   
691