写项目的时候肯定会遇到实现类似于iOS 的Navigation Controller或者Tab bar之类的界面。官方只有一个NavigatorIOS
的控件可以用,但是这个控件只能用在iOS平台,安卓的要另外重写,十分鸡肋。所以官方还提供了两个控件可以选择:react-navigation 和 react-native-navigation。这两个的区别我感觉网上写的很少,所以写这篇博客来记下两个区别。。。
当然如果懒得看完,可以直接用这个结论:用 react-navigation!!! 好用的多!!!
react-native-navigation react-native 版本需要大于 0.43,nmp 版本大于 3.0
安装 1 yarn add react-native-navigation@latest
iOS 安装 通过 /iOS/.xcodeproj 打开项目
Libraries
->Add files to [project name]
添加(Add) ./node_modules/react-native-navigation/ios/ReactNativeNavigation.xcodeproj
点击Build Phases
,在 Link Binary With Libraries
里添加 libReactNativeNavigation.a
点击Build Settings
,在Header Search Paths
里添加 $(SRCROOT)/../node_modules/react-native-navigation/ios
,确保是recursive
模式。
修改AppDelegate.m
如下
1 2 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 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { NSURL *jsCodeLocation; #ifdef DEBUG // jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"]; jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil]; #else jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; #endif // ********************************************** // *** DON'T MISS: THIS IS HOW WE BOOTSTRAP ***** // ********************************************** self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; self.window.backgroundColor = [UIColor whiteColor]; [[RCCManager sharedInstance] initBridgeWithBundleURL:jsCodeLocation launchOptions:launchOptions]; /* // original RN bootstrap - remove this part RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation moduleName:@"example" initialProperties:nil launchOptions:launchOptions]; self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; UIViewController *rootViewController = [UIViewController new]; rootViewController.view = rootView; self.window.rootViewController = rootViewController; [self.window makeKeyAndVisible]; */ return YES; }
Android 安装 在android/settings.gradle
里面添加:
1 2 include ': react-native-navigation' project(': react-native-navigation').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-navigation/android/app/')
更新android/app/build.gradle
文件如下:
1 2 3 4 5 6 7 8 9 10 11 12 android { compileSdkVersion 25 buildToolsVersion "25.0.1" ... } dependencies { compile fileTree(dir: "libs" , include: [ "*.jar" ] ) compile "com.android.support:appcompat-v7:23.0.1" compile "com.facebook.react:react-native:+" compile project(': react-native-navigation') }
修改 android/app/src/main/java/com/yourproject/MainActivity.java
文件,MainActivity 应该继承 com.reactnativenavigation.controllers.SplashActivity
而不是 ReactActivity
1 2 3 4 5 import com.reactnativenavigation.controllers.SplashActivity; public class MainActivity extends SplashActivity { }
MainApplication.java
文件添加以下内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import com.reactnativenavigation.NavigationApplication;public class MainApplication extends NavigationApplication { @Override public boolean isDebug () { return BuildConfig.DEBUG; } protected List<ReactPackage> getPackages () { return Arrays.<ReactPackage>asList( ); } @Override public List<ReactPackage> createAdditionalReactPackages () { return getPackages(); } }
更新 AndroidManifest.xml
把 android:name 的值改成 .MainApplication
1 2 3 4 <application android:name =".MainApplication" ... />
用法 这里我们实现三个页面来介绍react-native-navigation的用法。
1 2 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 import React , { Component } from 'react' ;import { AppRegistry , Text , View , StyleSheet , Button } from 'react-native' ;export default class FirstTabScreen extends Component { onPushAnother = () => { this .props .navigator .push ({ screen : 'example.PushedScreen' , title : 'Pushed Screen' }); }; render ( ) { return ( <View style ={styles.container} > <Button onPress ={this.onPushAnother} title ="Push Another Screen" /> <Text style ={styles.content} > first screen</Text > </View > ); } } const styles = StyleSheet .create ({ container : { flex : 1 , alignItems : 'center' , justifyContent : 'center' }, content : { textAlign : 'center' , marginTop : 10 , }, }); import React , { Component } from 'react' ;import { AppRegistry , Text , View , StyleSheet } from 'react-native' ;export default class SecondTabScreen extends Component { render ( ) { return ( <View style ={styles.container} > <Text style ={styles.content} > second screen</Text > </View > ); } } const styles = StyleSheet .create ({ container : { flex : 1 , alignItems : 'center' , justifyContent : 'center' }, content : { textAlign : 'center' , marginTop : 10 , }, });
以及 index.js
,这是react-native-navigation
中最重要的部分,没有之一。注意看这里的操作,通过Navigation.registerComponent
方法注册所有的页面,每个页面手动分了一个id,比如example.FirstTabScreen
就是“example.FirstTabScreen”
,之后如果用到页面就通过这个id把它调出来。而 registerScreens()
方法只能调用一次就是说你要把你项目中所有的页面全部在这里写一遍!!! 当时我也很震惊,哪有这么写框架的,一点也不优雅,但是它真是这么干的,而且官方的例子也是这么写的:
1 2 3 4 5 6 7 8 9 10 11 12 13 import { Navigation } from 'react-native-navigation' ;import FirstTabScreen from './FirstTabScreen' ;import SecondTabScreen from './SecondTabScreen' ;import PushedScreen from './PushedScreen' ;export function registerScreens ( ) { Navigation .registerComponent ('example.FirstTabScreen' , () => FirstTabScreen ); Navigation .registerComponent ('example.SecondTabScreen' , () => SecondTabScreen ); Navigation .registerComponent ('example.PushedScreen' , () => PushedScreen ); }
以上页面放到一个screen文件夹中。
然后index.ios.js
加入以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import { Navigation } from 'react-native-navigation' ;import { registerScreens } from './screens' ;registerScreens (); Navigation .startTabBasedApp ({ tabs : [ { label : 'One' , screen : 'example.FirstTabScreen' , title : 'Screen One' }, { label : 'Two' , screen : 'example.SecondTabScreen' , title : 'Screen Two' } ] });
效果
react-navigation 这个是airbnb团队开发的,个人感觉比react-native-navigation
好用,强烈推荐
安装 1 npm install --save react-navigation
or
1 yarn add react-navigation
修改index.ios.js
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 import React from 'react' ;import { AppRegistry , Text , } from 'react-native' ; import { StackNavigator } from 'react-navigation' ;class HomeScreen extends React.Component { static navigationOptions = { title : 'Welcome' , }; render ( ) { return <Text > Hello, Navigation!</Text > ; } } export default const SimpleApp = StackNavigator ({ Home : { screen : HomeScreen }, }); AppRegistry .registerComponent ('SimpleApp' , () => SimpleApp );
就可以了,十分方便
用法 这里我们同样用三个页面来介绍react-navigation的用法。
1 2 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 import React , { Component } from 'react' ;import { AppRegistry , Text , View , StyleSheet , Button } from 'react-native' ;import { StackNavigator } from 'react-navigation' ;import PushedScreen from './PushedScreen' class Fcreen extends Component { render ( ) { return ( <View style ={styles.container} > <Button onPress ={() => this.props.navigation.navigate('Pushed', {name: 'Pushed Screen'})} title="Push Another Screen" /> <Text style ={styles.content} > first screen</Text > </View > ); } } export default class FirstTabScreen extends Component { render ( ) { FPage = StackNavigator ({ FirstTabScreen : { screen : Fcreen , }, Pushed : { navigationOptions : ({ navigation } ) => ({ title : 'Pushed Screen' , }), screen : PushedScreen , }, }); return <FPage /> } } const styles = StyleSheet .create ({ container : { flex : 1 , alignItems : 'center' , justifyContent : 'center' }, content : { textAlign : 'center' , marginTop : 10 , }, }); import React , { Component } from 'react' ;import { AppRegistry , Text , View , StyleSheet } from 'react-native' ;export default class SecondTabScreen extends Component { render ( ) { return ( <View style ={styles.container} > <Text style ={styles.content} > second screen</Text > </View > ); } } const styles = StyleSheet .create ({ container : { flex : 1 , alignItems : 'center' , justifyContent : 'center' }, content : { textAlign : 'center' , marginTop : 10 , }, });
以及index.ios.js
或 index.android.js
1 2 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 import React from 'react' ;import { AppRegistry , Text , } from 'react-native' ; import { StackNavigator , TabNavigator } from 'react-navigation' ;import FirstTabScreen from './view/FirstTabScreen' import SecondTabScreen from './view/SecondTabScreen' class HomeScreen extends React.Component { static navigationOptions = { title : 'Welcome' , }; render ( ) { return <Text > Hello, Navigation!</Text > ; } } const test = TabNavigator ({ First : { screen : FirstTabScreen , }, Second : { screen : SecondTabScreen , }, }, { tabBarPosition : 'bottom' , animationEnabled : true , tabBarOptions : { activeTintColor : '#e91e63' , }, }); AppRegistry .registerComponent ('test' , () => test);
效果