React-Native-Navigation
Install
依據以下動作即可完成
Install
Basic Usage
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 
 | const { Navigation } = require('react-native-navigation');
 const React = require('react');
 const { View, Text, StyleSheet } = require('react-native');
 
 const HomeScreen = (props) => {
 return (
 <View style={styles.root}>
 <Text>Home Screen</Text>
 </View>
 );
 };
 
 
 HomeScreen.options = {
 topBar: {
 title: {
 text: 'Home',
 color: 'white'
 },
 background: {
 color: '#4d089a'
 }
 }
 }
 
 Navigation.registerComponent('Home', () => HomeScreen);
 
 Navigation.events().registerAppLaunchedListener(async () => {
 Navigation.setRoot({
 root: {
 stack: {
 children: [
 {
 component: {
 name: 'Home'
 }
 }
 ]
 }
 }
 });
 });
 
 const styles = StyleSheet.create({
 root: {
 flex: 1,
 alignItems: 'center',
 justifyContent: 'center',
 backgroundColor: 'whitesmoke'
 }
 });
 
 | 
:::info
Navigation.registerComponent 會建立一個 uniqueId CompoenntId 這個 Id 會是換頁的主要依據
:::
導頁
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 
 | const { Navigation } = require('react-native-navigation');
 const React = require('react');
 const { View, Text, StyleSheet } = require('react-native');
 const { Button } = require('react-native');
 
 const HomeScreen = (props) => {
 return (
 <View style={styles.root}>
 <Text>Home Screen</Text>
 <Button
 title='Push Settings Screen'
 color='#710ce3'
 onPress={() => Navigation.push(props.componentId, {
 component: {
 name: 'Settings',
 options: {
 topBar: {
 title: {
 text: 'Settings'
 }
 }
 }
 }
 })}/>
 </View>
 );
 };
 
 const SettingScreen = (props) => {
 return (
 <View style={styles.root}>
 <Text>Setting Screen</Text>
 </View>
 );
 };
 
 
 HomeScreen.options = {
 topBar: {
 title: {
 text: 'Home',
 color: 'white'
 },
 background: {
 color: '#4d089a'
 }
 }
 }
 
 Navigation.registerComponent('Home', () => HomeScreen);
 Navigation.registerComponent('Settings', () => SettingScreen);
 
 Navigation.events().registerAppLaunchedListener(async () => {
 Navigation.setRoot({
 root: {
 stack: {
 children: [
 {
 component: {
 name: 'Home'
 }
 }
 ]
 }
 }
 });
 });
 
 const styles = StyleSheet.create({
 root: {
 flex: 1,
 alignItems: 'center',
 justifyContent: 'center',
 backgroundColor: 'whitesmoke'
 }
 });
 
 | 
App Theme
使用的 Style Framwork 是 react-native-elements
裡面也有 Theme 
React Native Navigation 也可以設定 Theme
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | Navigation.setDefaultOptions({statusBar: {
 backgroundColor: '#4d089a'
 },
 topBar: {
 title: {
 color: 'white'
 },
 backButton: {
 color: 'white'
 },
 background: {
 color: '#4d089a'
 }
 }
 });
 
 | 
Tab Stack
一般的App 都會有 Bottom 的 Tap navigation
在 React Native Navigation 中
把剛剛的 Home Settings 頁面換成兩個 Tab Statck
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 
 | const { Navigation } = require('react-native-navigation');const React = require('react');
 const { View, Text, Button, StyleSheet } = require('react-native');
 
 const HomeScreen = (props) => {
 return (
 <View style={styles.root}>
 <Text>Hello React Native Navigation 👋</Text>
 
 <Button
 title='Push Settings Screen'
 color='#710ce3'
 onPress={() => Navigation.push(props.componentId, {
 component: {
 name: 'Settings'
 }
 })} />
 </View>
 );
 };
 HomeScreen.options = {
 topBar: {
 title: {
 text: 'Home'
 }
 },
 bottomTab: {
 text: 'Home'
 }
 };
 
 const SettingsScreen = () => {
 return (
 <View style={styles.root}>
 <Text>Settings Screen</Text>
 </View>
 );
 }
 SettingsScreen.options = {
 topBar: {
 title: {
 text: 'Settings'
 }
 },
 bottomTab: {
 text: 'Settings'
 }
 }
 
 Navigation.registerComponent('Home', () => HomeScreen);
 Navigation.registerComponent('Settings', () => SettingsScreen);
 
 Navigation.setDefaultOptions({
 statusBar: {
 backgroundColor: '#4d089a'
 },
 topBar: {
 title: {
 color: 'white'
 },
 backButton: {
 color: 'white'
 },
 background: {
 color: '#4d089a'
 }
 },
 bottomTab: {
 fontSize: 14,
 selectedFontSize: 14
 }
 });
 
 Navigation.events().registerAppLaunchedListener(async () => {
 Navigation.setRoot({
 root: {
 bottomTabs: {
 children: [
 {
 stack: {
 children: [
 {
 component: {
 name: 'Home'
 }
 },
 ]
 }
 },
 {
 stack: {
 children: [
 {
 component: {
 name: 'Settings'
 }
 }
 ]
 }
 }
 ]
 }
 }
 });
 });
 
 const styles = StyleSheet.create({
 root: {
 flex: 1,
 alignItems: 'center',
 justifyContent: 'center',
 backgroundColor: 'whitesmoke'
 }
 });
 
 | 
Bottom Tab 會有 Home 和 Settings
但是在 Home 會有 Button 
點擊後還是會 push Settings 進入 Home Stack
這是一般的 App Navigation 的邏輯
Replace Root
Navigation 也提供了覆蓋 Root Stack 的 function 
Navigation.setRoot(${rootObject})
執行這個 function 會將 Root 整個覆蓋
範例如下
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 
 | const { Navigation } = require('react-native-navigation');const React = require('react');
 const { View, Text, Button, StyleSheet } = require('react-native');
 
 const LoginScreen = () => {
 return (
 <View style={styles.root}>
 <Button
 title='Login'
 color='#710ce3'
 onPress={() => Navigation.setRoot(mainRoot)}
 />
 </View>
 );
 };
 
 const HomeScreen = (props) => {
 return (
 <View style={styles.root}>
 <Text>Hello React Native Navigation 👋</Text>
 
 <Button
 title='Push Settings Screen'
 color='#710ce3'
 onPress={() => Navigation.push(props.componentId, {
 component: {
 name: 'Settings'
 }
 })} />
 </View>
 );
 };
 HomeScreen.options = {
 topBar: {
 title: {
 text: 'Home'
 }
 },
 bottomTab: {
 text: 'Home'
 }
 };
 
 const SettingsScreen = () => {
 return (
 <View style={styles.root}>
 <Text>Settings Screen</Text>
 </View>
 );
 }
 SettingsScreen.options = {
 topBar: {
 title: {
 text: 'Settings'
 }
 },
 bottomTab: {
 text: 'Settings'
 }
 }
 
 Navigation.registerComponent('Login', () => LoginScreen);
 Navigation.registerComponent('Home', () => HomeScreen);
 Navigation.registerComponent('Settings', () => SettingsScreen);
 
 const mainRoot = {
 root: {
 bottomTabs: {
 children: [
 {
 stack: {
 children: [
 {
 component: {
 name: 'Home'
 }
 },
 ]
 }
 },
 {
 stack: {
 children: [
 {
 component: {
 name: 'Settings'
 }
 }
 ]
 }
 }
 ]
 }
 }
 };
 
 const loginRoot = {
 root: {
 component: {
 name: 'Login'
 }
 }
 };
 
 
 Navigation.setDefaultOptions({
 statusBar: {
 backgroundColor: '#4d089a'
 },
 topBar: {
 title: {
 color: 'white'
 },
 backButton: {
 color: 'white'
 },
 background: {
 color: '#4d089a'
 }
 },
 bottomTab: {
 fontSize: 14,
 selectedFontSize: 14
 }
 });
 Navigation.events().registerAppLaunchedListener(async () => {
 Navigation.setRoot(loginRoot);
 });
 
 const styles = StyleSheet.create({
 root: {
 flex: 1,
 alignItems: 'center',
 justifyContent: 'center',
 backgroundColor: 'whitesmoke'
 }
 });
 
 | 
基本上定義了一個 loginRoot 和 mainRoot 
在登入的時候如果成功則切換到 mainRoot
登出的時候則再度切換回 loginRoot
來簡單的實現了登入登出機制
但是在實際的產品中這樣卻是不足的
因為會先看到 LoginScreen
如果是登入狀態
加上在 React Native 讀取 AsyncStorage 的資料都是非同步的
會看到閃一下 再跳到 MainRoot
在使用者體驗上會很糟糕
所以會需要做一些調整來避免這個狀況
但是這篇篇幅太多
留著後面再說吧