Parcourir la 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 il y a 6 ans
Parent
révision
93de04e13f

+ 6
- 5
example/src/screens/types/CustomTopBar.js Voir le fichier

@@ -18,8 +18,8 @@ export default class CustomTopBar extends Component {
18 18
   render() {
19 19
     return (
20 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 23
         </TouchableOpacity>
24 24
       </View>
25 25
     );
@@ -30,15 +30,16 @@ const styles = StyleSheet.create({
30 30
   container: {
31 31
     flex: 1,
32 32
     justifyContent: 'center',
33
-    alignItems: 'center'
33
+    alignItems: 'center',
34
+    // backgroundColor: 'yellow'
34 35
   },
35 36
   button: {
36 37
     alignSelf: 'center',
37
-    backgroundColor: 'green'
38
+    // backgroundColor: 'green'
38 39
   },
39 40
   text: {
40 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 Voir le fichier

@@ -10,11 +10,41 @@ import CustomTopBar from './CustomTopBar';
10 10
 Navigation.registerComponent('example.CustomTopBar', () => CustomTopBar);
11 11
 
12 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 29
   componentDidMount() {
14 30
     this.props.navigator.setStyle({
15 31
       navBarCustomView: 'example.CustomTopBar',
16 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 Voir le fichier

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

+ 54
- 0
ios/RCCCustomTitleView.m Voir le fichier

@@ -11,12 +11,14 @@
11 11
 @interface RCCCustomTitleView ()
12 12
 @property (nonatomic, strong) UIView *subView;
13 13
 @property (nonatomic, strong) NSString *subViewAlign;
14
+@property float initialWidth;
14 15
 @end
15 16
 
16 17
 @implementation RCCCustomTitleView
17 18
 
18 19
 
19 20
 -(instancetype)initWithFrame:(CGRect)frame subView:(UIView*)subView alignment:(NSString*)alignment {
21
+    _initialWidth = frame.size.width;
20 22
     self = [super initWithFrame:frame];
21 23
     
22 24
     if (self) {
@@ -52,4 +54,56 @@
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 109
 @end

+ 12
- 2
ios/RCCViewController.m Voir le fichier

@@ -643,14 +643,16 @@ const NSInteger TRANSPARENT_NAVBAR_TAG = 78264803;
643 643
       NSDictionary *initialProps = self.navigatorStyle[@"navBarCustomViewInitialProps"];
644 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 649
       titleView.backgroundColor = [UIColor clearColor];
648 650
       reactView.backgroundColor = [UIColor clearColor];
649 651
       
650 652
       self.navigationItem.titleView = titleView;
651 653
       
652 654
       self.navigationItem.titleView.backgroundColor = [UIColor clearColor];
653
-      self.navigationItem.titleView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
655
+      self.navigationItem.titleView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
654 656
       self.navigationItem.titleView.clipsToBounds = YES;
655 657
     }
656 658
   }
@@ -676,6 +678,14 @@ const NSInteger TRANSPARENT_NAVBAR_TAG = 78264803;
676 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 690
 -(void)storeOriginalNavBarImages {
681 691