Skip to content

Commit b97ce93

Browse files
committed
[Nav] Add support for bar button icons and left buttons
Summary: NavigatorIOS supports four new properties: - **rightButtonImageSource:** The source of an image to display in the top right. This must be a static image since UINavigationController only supports UIImages. Adding support for UIImageViews (or arbitrary views) is more complicated because custom views do not fade on touch and do not have hit slop the same way that UIImage buttons do. Usage: `rightButtonImageSource: ix('ImageName')` - **backButtonImageSource:** Use a custom image for the back button. This does not replace the back caret (`<`) but instead replaces the text next to it. - **leftButtonTitle**: Text for the left nav button, which supersedes the previous nav item's back button when specified. The main use case for this is your initial screen/UIVC which has nothing to go back to (since it is the first VC on the stack) but need to display a left button. This does hide the back button if there would have been one otherwise. - **leftButtonImageSource:** Image source for the left button, super Closes facebook#263 Github Author: James Ide <ide@jameside.com> Test Plan: Imported from GitHub, without a `Test Plan:` line.
1 parent b8bf4d0 commit b97ce93

File tree

10 files changed

+247
-33
lines changed

10 files changed

+247
-33
lines changed

Examples/UIExplorer/ImageMocks.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,8 @@ declare module 'image!uie_thumb_selected' {
3939
declare var uri: string;
4040
declare var isStatic: boolean;
4141
}
42+
43+
declare module 'image!NavBarButtonPlus' {
44+
declare var uri: string;
45+
declare var isStatic: boolean;
46+
}

Examples/UIExplorer/NavigatorIOSExample.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ var React = require('react-native');
1919
var ViewExample = require('./ViewExample');
2020
var createExamplePage = require('./createExamplePage');
2121
var {
22+
AlertIOS,
2223
PixelRatio,
2324
ScrollView,
2425
StyleSheet,
@@ -92,6 +93,30 @@ var NavigatorIOSExample = React.createClass({
9293
}
9394
});
9495
})}
96+
{this._renderRow('Custom Left & Right Icons', () => {
97+
this.props.navigator.push({
98+
title: NavigatorIOSExample.title,
99+
component: EmptyPage,
100+
leftButtonTitle: 'Custom Left',
101+
onLeftButtonPress: () => this.props.navigator.pop(),
102+
rightButtonIcon: require('image!NavBarButtonPlus'),
103+
onRightButtonPress: () => {
104+
AlertIOS.alert(
105+
'Bar Button Action',
106+
'Recognized a tap on the bar button icon',
107+
[
108+
{
109+
text: 'OK',
110+
onPress: () => console.log('Tapped OK'),
111+
},
112+
]
113+
);
114+
},
115+
passProps: {
116+
text: 'This page has an icon for the right button in the nav bar',
117+
}
118+
});
119+
})}
95120
{this._renderRow('Pop', () => {
96121
this.props.navigator.pop();
97122
})}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{
2+
"images" : [
3+
{
4+
"idiom" : "universal",
5+
"scale" : "1x"
6+
},
7+
{
8+
"idiom" : "universal",
9+
"scale" : "2x"
10+
},
11+
{
12+
"idiom" : "universal",
13+
"filename" : "NavBarButtonPlus@3x.png",
14+
"scale" : "3x"
15+
}
16+
],
17+
"info" : {
18+
"version" : 1,
19+
"author" : "xcode"
20+
}
21+
}
166 Bytes
Loading

Libraries/Components/Navigation/NavigatorIOS.ios.js

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
'use strict';
1313

1414
var EventEmitter = require('EventEmitter');
15+
var Image = require('Image');
1516
var React = require('React');
1617
var ReactIOSViewAttributes = require('ReactIOSViewAttributes');
1718
var RCTNavigatorManager = require('NativeModules').NavigatorManager;
@@ -47,11 +48,16 @@ var RCTNavigatorItem = createReactIOSNativeComponentClass({
4748
// NavigatorIOS does not use them all, because some are problematic
4849
title: true,
4950
barTintColor: true,
51+
leftButtonIcon: true,
52+
leftButtonTitle: true,
53+
onNavLeftButtonTap: true,
54+
rightButtonIcon: true,
5055
rightButtonTitle: true,
5156
onNavRightButtonTap: true,
57+
backButtonIcon: true,
58+
backButtonTitle: true,
5259
tintColor: true,
5360
navigationBarHidden: true,
54-
backButtonTitle: true,
5561
titleTextColor: true,
5662
style: true,
5763
},
@@ -79,7 +85,12 @@ type Route = {
7985
title: string;
8086
passProps: Object;
8187
backButtonTitle: string;
88+
backButtonIcon: Object;
89+
leftButtonTitle: string;
90+
leftButtonIcon: Object;
91+
onLeftButtonPress: Function;
8292
rightButtonTitle: string;
93+
rightButtonIcon: Object;
8394
onRightButtonPress: Function;
8495
wrapperStyle: any;
8596
};
@@ -212,13 +223,40 @@ var NavigatorIOS = React.createClass({
212223
*/
213224
passProps: PropTypes.object,
214225

226+
/**
227+
* If set, the left header button image will appear with this source. Note
228+
* that this doesn't apply for the header of the current view, but the
229+
* ones of the views that are pushed afterward.
230+
*/
231+
backButtonIcon: Image.propTypes.source,
232+
215233
/**
216234
* If set, the left header button will appear with this name. Note that
217235
* this doesn't apply for the header of the current view, but the ones
218236
* of the views that are pushed afterward.
219237
*/
220238
backButtonTitle: PropTypes.string,
221239

240+
/**
241+
* If set, the left header button image will appear with this source
242+
*/
243+
leftButtonIcon: Image.propTypes.source,
244+
245+
/**
246+
* If set, the left header button will appear with this name
247+
*/
248+
leftButtonTitle: PropTypes.string,
249+
250+
/**
251+
* Called when the left header button is pressed
252+
*/
253+
onLeftButtonPress: PropTypes.func,
254+
255+
/**
256+
* If set, the right header button image will appear with this source
257+
*/
258+
rightButtonIcon: Image.propTypes.source,
259+
222260
/**
223261
* If set, the right header button will appear with this name
224262
*/
@@ -560,7 +598,12 @@ var NavigatorIOS = React.createClass({
560598
this.props.itemWrapperStyle,
561599
route.wrapperStyle
562600
]}
601+
backButtonIcon={this._imageNameFromSource(route.backButtonIcon)}
563602
backButtonTitle={route.backButtonTitle}
603+
leftButtonIcon={this._imageNameFromSource(route.leftButtonIcon)}
604+
leftButtonTitle={route.leftButtonTitle}
605+
onNavLeftButtonTap={route.onLeftButtonPress}
606+
rightButtonIcon={this._imageNameFromSource(route.rightButtonIcon)}
564607
rightButtonTitle={route.rightButtonTitle}
565608
onNavRightButtonTap={route.onRightButtonPress}
566609
navigationBarHidden={this.props.navigationBarHidden}
@@ -577,6 +620,10 @@ var NavigatorIOS = React.createClass({
577620
);
578621
},
579622

623+
_imageNameFromSource: function(source: ?Object) {
624+
return source ? source.uri : undefined;
625+
},
626+
580627
renderNavigationStackItems: function() {
581628
var shouldRecurseToNavigator =
582629
this.state.makingNavigatorRequest ||

React/Modules/RCTUIManager.m

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1159,6 +1159,12 @@ - (NSDictionary *)customBubblingEventTypes
11591159
@"captured": @"onNavigationCompleteCapture"
11601160
}
11611161
},
1162+
@"topNavLeftButtonTap": @{
1163+
@"phasedRegistrationNames": @{
1164+
@"bubbled": @"onNavLeftButtonTap",
1165+
@"captured": @"onNavLefttButtonTapCapture"
1166+
}
1167+
},
11621168
@"topNavRightButtonTap": @{
11631169
@"phasedRegistrationNames": @{
11641170
@"bubbled": @"onNavRightButtonTap",

React/Views/RCTNavItem.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,19 @@
1212
@interface RCTNavItem : UIView
1313

1414
@property (nonatomic, copy) NSString *title;
15+
@property (nonatomic, strong) UIImage *leftButtonIcon;
16+
@property (nonatomic, copy) NSString *leftButtonTitle;
17+
@property (nonatomic, strong) UIImage *rightButtonIcon;
1518
@property (nonatomic, copy) NSString *rightButtonTitle;
19+
@property (nonatomic, strong) UIImage *backButtonIcon;
1620
@property (nonatomic, copy) NSString *backButtonTitle;
1721
@property (nonatomic, assign) BOOL navigationBarHidden;
18-
@property (nonatomic, copy) UIColor *tintColor;
19-
@property (nonatomic, copy) UIColor *barTintColor;
20-
@property (nonatomic, copy) UIColor *titleTextColor;
22+
@property (nonatomic, strong) UIColor *tintColor;
23+
@property (nonatomic, strong) UIColor *barTintColor;
24+
@property (nonatomic, strong) UIColor *titleTextColor;
25+
26+
@property (nonatomic, readonly) UIBarButtonItem *backButtonItem;
27+
@property (nonatomic, readonly) UIBarButtonItem *leftButtonItem;
28+
@property (nonatomic, readonly) UIBarButtonItem *rightButtonItem;
2129

2230
@end

React/Views/RCTNavItem.m

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,104 @@
1111

1212
@implementation RCTNavItem
1313

14-
@end
14+
@synthesize backButtonItem = _backButtonItem;
15+
@synthesize leftButtonItem = _leftButtonItem;
16+
@synthesize rightButtonItem = _rightButtonItem;
17+
18+
- (void)setBackButtonTitle:(NSString *)backButtonTitle
19+
{
20+
_backButtonTitle = backButtonTitle;
21+
_backButtonItem = nil;
22+
}
23+
24+
- (void)setBackButtonIcon:(UIImage *)backButtonIcon
25+
{
26+
_backButtonIcon = backButtonIcon;
27+
_backButtonItem = nil;
28+
}
29+
30+
- (UIBarButtonItem *)backButtonItem
31+
{
32+
if (!_backButtonItem) {
33+
if (_backButtonIcon) {
34+
_backButtonItem = [[UIBarButtonItem alloc] initWithImage:_backButtonIcon
35+
style:UIBarButtonItemStylePlain
36+
target:nil
37+
action:nil];
38+
} else if (_backButtonTitle.length) {
39+
_backButtonItem = [[UIBarButtonItem alloc] initWithTitle:_backButtonTitle
40+
style:UIBarButtonItemStylePlain
41+
target:nil
42+
action:nil];
43+
} else {
44+
_backButtonItem = nil;
45+
}
46+
}
47+
return _backButtonItem;
48+
}
49+
50+
- (void)setLeftButtonTitle:(NSString *)leftButtonTitle
51+
{
52+
_leftButtonTitle = leftButtonTitle;
53+
_leftButtonItem = nil;
54+
}
55+
56+
- (void)setLeftButtonIcon:(UIImage *)leftButtonIcon
57+
{
58+
_leftButtonIcon = leftButtonIcon;
59+
_leftButtonIcon = nil;
60+
}
1561

62+
- (UIBarButtonItem *)leftButtonItem
63+
{
64+
if (!_leftButtonItem) {
65+
if (_leftButtonIcon) {
66+
_leftButtonItem = [[UIBarButtonItem alloc] initWithImage:_leftButtonIcon
67+
style:UIBarButtonItemStylePlain
68+
target:nil
69+
action:nil];
70+
} else if (_leftButtonTitle.length) {
71+
_leftButtonItem = [[UIBarButtonItem alloc] initWithTitle:_leftButtonTitle
72+
style:UIBarButtonItemStylePlain
73+
target:nil
74+
action:nil];
75+
} else {
76+
_leftButtonItem = nil;
77+
}
78+
}
79+
return _leftButtonItem;
80+
}
81+
82+
- (void)setRightButtonTitle:(NSString *)rightButtonTitle
83+
{
84+
_rightButtonTitle = rightButtonTitle;
85+
_rightButtonItem = nil;
86+
}
87+
88+
- (void)setRightButtonIcon:(UIImage *)rightButtonIcon
89+
{
90+
_rightButtonIcon = rightButtonIcon;
91+
_rightButtonItem = nil;
92+
}
93+
94+
- (UIBarButtonItem *)rightButtonItem
95+
{
96+
if (!_rightButtonItem) {
97+
if (_rightButtonIcon) {
98+
_rightButtonItem = [[UIBarButtonItem alloc] initWithImage:_rightButtonIcon
99+
style:UIBarButtonItemStylePlain
100+
target:nil
101+
action:nil];
102+
} else if (_rightButtonTitle.length) {
103+
_rightButtonItem = [[UIBarButtonItem alloc] initWithTitle:_rightButtonTitle
104+
style:UIBarButtonItemStylePlain
105+
target:nil
106+
action:nil];
107+
} else {
108+
_rightButtonItem = nil;
109+
}
110+
}
111+
return _rightButtonItem;
112+
}
113+
114+
@end

React/Views/RCTNavItemManager.m

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,20 @@ - (UIView *)view
2121
return [[RCTNavItem alloc] init];
2222
}
2323

24+
RCT_EXPORT_VIEW_PROPERTY(navigationBarHidden, BOOL)
25+
RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor)
26+
RCT_EXPORT_VIEW_PROPERTY(barTintColor, UIColor)
27+
2428
RCT_EXPORT_VIEW_PROPERTY(title, NSString)
25-
RCT_EXPORT_VIEW_PROPERTY(rightButtonTitle, NSString);
26-
RCT_EXPORT_VIEW_PROPERTY(backButtonTitle, NSString);
27-
RCT_EXPORT_VIEW_PROPERTY(navigationBarHidden, BOOL);
28-
RCT_EXPORT_VIEW_PROPERTY(tintColor, UIColor);
29-
RCT_EXPORT_VIEW_PROPERTY(barTintColor, UIColor);
30-
RCT_EXPORT_VIEW_PROPERTY(titleTextColor, UIColor);
29+
RCT_EXPORT_VIEW_PROPERTY(titleTextColor, UIColor)
30+
31+
RCT_EXPORT_VIEW_PROPERTY(backButtonIcon, UIImage)
32+
RCT_EXPORT_VIEW_PROPERTY(backButtonTitle, NSString)
33+
34+
RCT_EXPORT_VIEW_PROPERTY(leftButtonTitle, NSString)
35+
RCT_EXPORT_VIEW_PROPERTY(leftButtonIcon, UIImage)
36+
37+
RCT_EXPORT_VIEW_PROPERTY(rightButtonIcon, UIImage)
38+
RCT_EXPORT_VIEW_PROPERTY(rightButtonTitle, NSString)
3139

3240
@end

0 commit comments

Comments
 (0)