|
@@ -11,6 +11,8 @@ App-wide support for 100% native navigation with an easy cross-platform interfac
|
11
|
11
|
* [Screen API](#screen-api)
|
12
|
12
|
* [Styling the navigator](#styling-the-navigator)
|
13
|
13
|
* [Adding buttons to the navigator](#adding-buttons-to-the-navigator)
|
|
14
|
+* [Release Notes](RELEASES.md)
|
|
15
|
+* [License](#license)
|
14
|
16
|
|
15
|
17
|
## Installation - iOS
|
16
|
18
|
|
|
@@ -35,7 +37,10 @@ Coming soon, not yet supported
|
35
|
37
|
|
36
|
38
|
## Usage
|
37
|
39
|
|
38
|
|
-If you don't like reading, just jump into the fully working [example project](https://github.com/wix/react-native-navigation/tree/master/example).
|
|
40
|
+If you don't like reading, just jump into the fully working example projects:
|
|
41
|
+
|
|
42
|
+* [example](example) - Example project showing the best practice use of this package. Shows many navigation features.
|
|
43
|
+* [redux-example](example-redux) - Best practice use of this package in a [redux](https://github.com/reactjs/redux)-based. project
|
39
|
44
|
|
40
|
45
|
#### Step 1 - Change the way your app starts
|
41
|
46
|
|
|
@@ -44,17 +49,15 @@ This would normally go in your `index.ios.js`
|
44
|
49
|
```js
|
45
|
50
|
import { Navigation } from 'react-native-navigation';
|
46
|
51
|
|
47
|
|
-// import the components for your root screens (or the packager will not bundle them)
|
48
|
|
-// they all need to be registered with Navigation.registerScreen
|
49
|
|
-import './FirstTabScreen';
|
50
|
|
-import './SecondTabScreen';
|
|
52
|
+import { registerScreens } from './screens';
|
|
53
|
+registerScreens(); // this is where you register all of your app's screens
|
51
|
54
|
|
52
|
55
|
// start the app
|
53
|
56
|
Navigation.startTabBasedApp({
|
54
|
57
|
tabs: [
|
55
|
58
|
{
|
56
|
59
|
label: 'One',
|
57
|
|
- screen: 'example.FirstTabScreen',
|
|
60
|
+ screen: 'example.FirstTabScreen', // this is a registered name for a screen
|
58
|
61
|
icon: require('../img/one.png'),
|
59
|
62
|
selectedIcon: require('../img/one_selected.png'),
|
60
|
63
|
title: 'Screen One'
|
|
@@ -70,33 +73,25 @@ Navigation.startTabBasedApp({
|
70
|
73
|
});
|
71
|
74
|
```
|
72
|
75
|
|
73
|
|
-#### Step 2 - Slightly modify your screen components
|
74
|
|
-
|
75
|
|
-Every screen that you want to be able to place in a tab, push to the navigation stack or present modally needs to follow two basic conventions:
|
76
|
|
-
|
77
|
|
-1. Normally your React components extend `React.Component`, in order to get access to the `navigator` instance you need to extend `Screen` instead.
|
|
76
|
+#### Step 2 - Register all of your screen components
|
78
|
77
|
|
79
|
|
-2. You need to register your component since it's displayed as a separate React root. Register a unique ID with `Navigation.registerScreen`.
|
|
78
|
+Every screen that you want to be able to place in a tab, push to the navigation stack or present modally needs to be registered. We recommend doing this in a central place, like [`screens/index.js`](example/src/screens/index.js).
|
80
|
79
|
|
81
|
80
|
> Note: Since your screens will potentially be bundled with other packages, your registered name must be **unique**! Follow a namespacing convention like `packageName.ScreenName`.
|
82
|
81
|
|
83
|
82
|
```js
|
84
|
|
-import { Navigation, Screen } from 'react-native-navigation';
|
|
83
|
+import { Navigation } from 'react-native-navigation';
|
85
|
84
|
|
86
|
|
-class ExampleScreen extends Screen {
|
87
|
|
- static navigatorStyle = {}; // style the navigator for this screen (optional)
|
88
|
|
- constructor(props) {
|
89
|
|
- super(props);
|
90
|
|
- }
|
91
|
|
- render() {
|
92
|
|
- return (
|
93
|
|
- <View style={styles.container}>...</View>
|
94
|
|
- );
|
95
|
|
- }
|
96
|
|
-}
|
|
85
|
+import FirstTabScreen from './FirstTabScreen';
|
|
86
|
+import SecondTabScreen from './SecondTabScreen';
|
|
87
|
+import PushedScreen from './PushedScreen';
|
97
|
88
|
|
98
|
|
-// register all screens with Navigation.registerScreen
|
99
|
|
-Navigation.registerScreen('example.ScreenOne', () => ExampleScreen);
|
|
89
|
+// register all screens of the app (including internal ones)
|
|
90
|
+export function registerScreens() {
|
|
91
|
+ Navigation.registerComponent('example.FirstTabScreen', () => FirstTabScreen);
|
|
92
|
+ Navigation.registerComponent('example.SecondTabScreen', () => SecondTabScreen);
|
|
93
|
+ Navigation.registerComponent('example.PushedScreen', () => PushedScreen);
|
|
94
|
+}
|
100
|
95
|
```
|
101
|
96
|
|
102
|
97
|
## Top Level API
|
|
@@ -107,12 +102,16 @@ Navigation.registerScreen('example.ScreenOne', () => ExampleScreen);
|
107
|
102
|
import { Navigation } from 'react-native-navigation';
|
108
|
103
|
```
|
109
|
104
|
|
110
|
|
- * **registerScreen(screenID, generator)**
|
|
105
|
+ * **registerComponent(screenID, generator, store = undefined, Provider = undefined)**
|
111
|
106
|
|
112
|
|
-Every screen used must be registered with a unique name.
|
|
107
|
+Every screen component in your app must be registered with a unique name. The component itself is a traditional React component extending `React.Component`.
|
113
|
108
|
|
114
|
109
|
```js
|
115
|
|
-Navigation.registerScreen('example.FirstTabScreen', () => FirstTabScreen);
|
|
110
|
+// not using redux (just ignore the last 2 arguments)
|
|
111
|
+Navigation.registerComponent('example.FirstTabScreen', () => FirstTabScreen);
|
|
112
|
+
|
|
113
|
+// using redux, pass your store and the Provider object from react-redux
|
|
114
|
+Navigation.registerComponent('example.FirstTabScreen', () => FirstTabScreen, store, Provider);
|
116
|
115
|
```
|
117
|
116
|
|
118
|
117
|
* **startTabBasedApp(params)**
|
|
@@ -193,18 +192,26 @@ Dismiss the current modal.
|
193
|
192
|
Navigation.dismissModal({
|
194
|
193
|
animationType: 'slide-down' // 'none' / 'slide-down' , dismiss animation for the modal (optional, default 'slide-down')
|
195
|
194
|
});
|
|
195
|
+```
|
|
196
|
+
|
|
197
|
+ * **registerScreen(screenID, generator)**
|
|
198
|
+
|
|
199
|
+This is an internal function you probably don't want to use directly. If your screen components extend `Screen` directly (`import { Screen } from 'react-native-navigation'`), you can register them directly with `registerScreen` instead of with `registerComponent`. The main benefit of using `registerComponent` is that it wraps your regular screen component with a `Screen` automatically.
|
|
200
|
+
|
|
201
|
+```js
|
|
202
|
+Navigation.registerScreen('example.AdvancedScreen', () => AdvancedScreen);
|
196
|
203
|
```
|
197
|
204
|
|
198
|
205
|
## Screen API
|
199
|
206
|
|
200
|
|
-This API is relevant when in a screen context - it allows a screen to push other screens, pop screens, change its navigator style, etc. Access to this API is available through the `navigator` object. When your screen components extend `Screen`, they have `this.navigator` available and initialized.
|
|
207
|
+This API is relevant when in a screen component context - it allows a screen to push other screens, pop screens, change its navigator style, etc. Access to this API is available through the `navigator` object that is passed to your component through `props`.
|
201
|
208
|
|
202
|
209
|
* **push(params)**
|
203
|
210
|
|
204
|
211
|
Push a new screen into this screen's navigation stack.
|
205
|
212
|
|
206
|
213
|
```js
|
207
|
|
-this.navigator.push({
|
|
214
|
+this.props.navigator.push({
|
208
|
215
|
screen: 'example.ScreenThree', // unique ID registered with Navigation.registerScreen
|
209
|
216
|
title: undefined, // navigation bar title of the pushed screen (optional)
|
210
|
217
|
passProps: {}, // simple serializable object that will pass as props to the pushed screen (optional)
|
|
@@ -219,7 +226,7 @@ this.navigator.push({
|
219
|
226
|
Pop the top screen from this screen's navigation stack.
|
220
|
227
|
|
221
|
228
|
```js
|
222
|
|
-this.navigator.pop({
|
|
229
|
+this.props.navigator.pop({
|
223
|
230
|
animated: true // does the pop have transition animation or does it happen immediately (optional)
|
224
|
231
|
});
|
225
|
232
|
```
|
|
@@ -229,7 +236,7 @@ this.navigator.pop({
|
229
|
236
|
Pop all the screens until the root from this screen's navigation stack.
|
230
|
237
|
|
231
|
238
|
```js
|
232
|
|
-this.navigator.popToRoot({
|
|
239
|
+this.props.navigator.popToRoot({
|
233
|
240
|
animated: true // does the pop have transition animation or does it happen immediately (optional)
|
234
|
241
|
});
|
235
|
242
|
```
|
|
@@ -239,7 +246,7 @@ this.navigator.popToRoot({
|
239
|
246
|
Reset the screen's navigation stack to a new screen (the stack root is changed).
|
240
|
247
|
|
241
|
248
|
```js
|
242
|
|
-this.navigator.resetTo({
|
|
249
|
+this.props.navigator.resetTo({
|
243
|
250
|
screen: 'example.ScreenThree', // unique ID registered with Navigation.registerScreen
|
244
|
251
|
title: undefined, // navigation bar title of the pushed screen (optional)
|
245
|
252
|
passProps: {}, // simple serializable object that will pass as props to the pushed screen (optional)
|
|
@@ -253,7 +260,7 @@ this.navigator.resetTo({
|
253
|
260
|
Show a screen as a modal.
|
254
|
261
|
|
255
|
262
|
```js
|
256
|
|
-this.navigator.showModal({
|
|
263
|
+this.props.navigator.showModal({
|
257
|
264
|
screen: "example.ModalScreen", // unique ID registered with Navigation.registerScreen
|
258
|
265
|
title: "Modal", // title of the screen as appears in the nav bar (optional)
|
259
|
266
|
passProps: {}, // simple serializable object that will pass as props to the modal (optional)
|
|
@@ -267,9 +274,18 @@ this.navigator.showModal({
|
267
|
274
|
Dismiss the current modal.
|
268
|
275
|
|
269
|
276
|
```js
|
270
|
|
-this.navigator.dismissModal({
|
|
277
|
+this.props.navigator.dismissModal({
|
271
|
278
|
animationType: 'slide-down' // 'none' / 'slide-down' , dismiss animation for the modal (optional, default 'slide-down')
|
272
|
279
|
});
|
|
280
|
+```
|
|
281
|
+
|
|
282
|
+ * **setOnNavigatorEvent(callback)**
|
|
283
|
+
|
|
284
|
+Set a handler for navigator events (like nav button press). This would normally go in your component constructor.
|
|
285
|
+
|
|
286
|
+```js
|
|
287
|
+// this.onNavigatorEvent will be our handler
|
|
288
|
+this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this));
|
273
|
289
|
```
|
274
|
290
|
|
275
|
291
|
* **setButtons(params = {})**
|
|
@@ -277,7 +293,7 @@ this.navigator.dismissModal({
|
277
|
293
|
Set buttons dynamically on the navigator. If your buttons don't change during runtime, see "Adding buttons to the navigator" below to add them using `static navigatorButtons = {...};`.
|
278
|
294
|
|
279
|
295
|
```js
|
280
|
|
-this.navigator.setButtons({
|
|
296
|
+this.props.navigator.setButtons({
|
281
|
297
|
leftButtons: [], // see "Adding buttons to the navigator" below for format (optional)
|
282
|
298
|
rightButtons: [], // see "Adding buttons to the navigator" below for format (optional)
|
283
|
299
|
animated: true // does the change have transition animation or does it happen immediately (optional)
|
|
@@ -289,7 +305,7 @@ this.navigator.setButtons({
|
289
|
305
|
Set the nav bar title dynamically. If your title doesn't change during runtime, set it when the screen is defined / pushed.
|
290
|
306
|
|
291
|
307
|
```js
|
292
|
|
-this.navigator.setTitle({
|
|
308
|
+this.props.navigator.setTitle({
|
293
|
309
|
title: "Dynamic Title" // the new title of the screen as appears in the nav bar
|
294
|
310
|
});
|
295
|
311
|
```
|
|
@@ -299,7 +315,7 @@ this.navigator.setTitle({
|
299
|
315
|
Toggle the side menu drawer assuming you have one in your app.
|
300
|
316
|
|
301
|
317
|
```js
|
302
|
|
-this.navigator.toggleDrawer({
|
|
318
|
+this.props.navigator.toggleDrawer({
|
303
|
319
|
side: 'left', // the side of the drawer since you can have two, 'left' / 'right'
|
304
|
320
|
animated: true // does the toggle have transition animation or does it happen immediately (optional)
|
305
|
321
|
});
|
|
@@ -307,7 +323,25 @@ this.navigator.toggleDrawer({
|
307
|
323
|
|
308
|
324
|
## Styling the navigator
|
309
|
325
|
|
310
|
|
-You can style the navigator appearance and behavior by passing a `navigatorStyle` object. This object can be passed when the screen is originally created; can be defined per-screen in the `static navigatorStyle = {};` on `Screen`; and can be overridden when a screen is pushed.
|
|
326
|
+You can style the navigator appearance and behavior by passing a `navigatorStyle` object. This object can be passed when the screen is originally created; can be defined per-screen by setting `static navigatorStyle = {};` on the screen component; and can be overridden when a screen is pushed.
|
|
327
|
+
|
|
328
|
+The easiest way to style your screen is by adding `static navigatorStyle = {};` to your screen React component definition.
|
|
329
|
+
|
|
330
|
+```js
|
|
331
|
+export default class StyledScreen extends Component {
|
|
332
|
+ static navigatorStyle = {
|
|
333
|
+ drawUnderNavBar: true,
|
|
334
|
+ navBarTranslucent: true
|
|
335
|
+ };
|
|
336
|
+ constructor(props) {
|
|
337
|
+ super(props);
|
|
338
|
+ }
|
|
339
|
+ render() {
|
|
340
|
+ return (
|
|
341
|
+ <View style={{flex: 1}}>...</View>
|
|
342
|
+ );
|
|
343
|
+ }
|
|
344
|
+```
|
311
|
345
|
|
312
|
346
|
#### Style object format
|
313
|
347
|
|
|
@@ -334,44 +368,12 @@ You can style the navigator appearance and behavior by passing a `navigatorStyle
|
334
|
368
|
|
335
|
369
|
All supported styles are defined [here](https://github.com/wix/react-native-controllers#styling-navigation). There's also an example project there showcasing all the different styles.
|
336
|
370
|
|
337
|
|
-#### Screen-specific style example
|
338
|
|
-
|
339
|
|
-Define a screen-specific style by adding `static navigatorStyle = {...};` to the Screen definition.
|
340
|
|
-
|
341
|
|
-```js
|
342
|
|
-class StyledScreen extends Screen {
|
343
|
|
- static navigatorStyle = {
|
344
|
|
- drawUnderNavBar: true,
|
345
|
|
- drawUnderTabBar: true,
|
346
|
|
- navBarTranslucent: true
|
347
|
|
- };
|
348
|
|
- constructor(props) {
|
349
|
|
- super(props);
|
350
|
|
- }
|
351
|
|
- render() {
|
352
|
|
- return (
|
353
|
|
- <View style={{flex: 1}}>...</View>
|
354
|
|
- );
|
355
|
|
- }
|
356
|
|
-```
|
357
|
|
-
|
358
|
371
|
## Adding buttons to the navigator
|
359
|
372
|
|
360
|
|
-Nav bar buttons can be defined per-screen by adding `static navigatorButtons = {...};` on the Screen definition. Handle onPress events for the buttons by overriding the Screen's `onNavigatorEvent(event)` method.
|
361
|
|
-
|
362
|
|
-#### Buttons object format
|
363
|
|
-
|
364
|
|
-```js
|
365
|
|
-{
|
366
|
|
- rightButtons: [], // buttons for the right side of the nav bar (optional)
|
367
|
|
- leftButtons: [] // buttons for the left side of the nav bar (optional)
|
368
|
|
-}
|
369
|
|
-```
|
370
|
|
-
|
371
|
|
-#### Screen-specific buttons example
|
|
373
|
+Nav bar buttons can be defined per-screen by adding `static navigatorButtons = {...};` on the screen component definition. Handle onPress events for the buttons by setting your handler with `navigator.setOnNavigatorEvent(callback)`.
|
372
|
374
|
|
373
|
375
|
```js
|
374
|
|
-class FirstTabScreen extends Screen {
|
|
376
|
+class FirstTabScreen extends Component {
|
375
|
377
|
static navigatorButtons = {
|
376
|
378
|
rightButtons: [
|
377
|
379
|
{
|
|
@@ -387,6 +389,8 @@ class FirstTabScreen extends Screen {
|
387
|
389
|
};
|
388
|
390
|
constructor(props) {
|
389
|
391
|
super(props);
|
|
392
|
+ // if you want to listen on navigator events, set this up
|
|
393
|
+ this.props.navigator.setOnNavigatorEvent(this.onNavigatorEvent.bind(this));
|
390
|
394
|
}
|
391
|
395
|
onNavigatorEvent(event) { // this is the onPress handler for the two buttons together
|
392
|
396
|
if (event.id == 'edit') { // this is the same id field from the static navigatorButtons definition
|
|
@@ -402,3 +406,23 @@ class FirstTabScreen extends Screen {
|
402
|
406
|
);
|
403
|
407
|
}
|
404
|
408
|
```
|
|
409
|
+
|
|
410
|
+#### Buttons object format
|
|
411
|
+
|
|
412
|
+```js
|
|
413
|
+{
|
|
414
|
+ rightButtons: [{ // buttons for the right side of the nav bar (optional)
|
|
415
|
+ title: 'Edit', // if you want a textual button
|
|
416
|
+ icon: require('../../img/navicon_edit.png'), // if you want an image button
|
|
417
|
+ id: 'compose', // id of the button which will pass to your press event handler
|
|
418
|
+ testID: 'e2e_is_awesome' // if you have e2e tests, use this to find your button
|
|
419
|
+ }],
|
|
420
|
+ leftButtons: [] // buttons for the left side of the nav bar (optional)
|
|
421
|
+}
|
|
422
|
+```
|
|
423
|
+
|
|
424
|
+## License
|
|
425
|
+
|
|
426
|
+The MIT License.
|
|
427
|
+
|
|
428
|
+See [LICENSE](LICENSE)
|