前面的章节重点讲解了关于React Native环境的搭建及开发APP所具备的知识,接下来会讲React Native核心的库React Native Navigation。
1.环境搭建
再提醒一句,环境搭建很重要。
如何才算搭好了环境?简单理解就是成功运行开发环境
和打包环境
。
开发环境:
//成功运行在Simulator上
react-native run-ios
//成功运行在Genymotion上
react-native run-android
打包环境:
//成功打包apk且在android真机运行
cd android && ./gradlew assembleRelease
//成功打包ipa且在ios真机运行
Xcode,点击Archive
在开始React Native的学习时,开发的环境必须要有,想成功上线项目,打包环境也必须要有。 当时我本打算将开发和打包环境放在同一个项目里面,这样自以为维护起来方便,毕竟在一个项目里。后来我迟迟没搭建成功,一直在报错。错误如下:
这个看了说是Mac最新系统导致的问题,需要重装Wtachman,但是我卸载重装Watchman多次,继续报这个错,于是我放弃了在同一个项目里搭开发环境和打包环境。
因此,我因祸得福的将两个环境独立开来,其实这样做反而更好,理由很简单,开发的时候出的各种问题不会影响打包的环境
。等开发调试结束后,在把改过的源代码替换到打包环境里面就可以直接打包了。
2.React-Native-Navigation
下面重点详细讲解React-Native-Navigation这个框架。
为什么要使用它呢?
原因很简单,Facebook提供的Navigator
组件是用JS实现的,虽然跨两个终端,但在性能上不够理想,其次提供的NavigatorIOS
、TabBarIOS
组件虽然是原生实现的,但都只有iOS端的,Android没有。于是乎react-native-navigation
是最好的解决方案。
其官网是:https://github.com/wix/react-native-navigation
React Native Navigation provides 100% native platform navigation on both iOS and Android for React Native apps. 因此性能和体验上是毋庸置疑的。
总结其特点是:
- 跨平台,同时指出Andoid和iOS
- 原生实现,性能优异
- 功能丰富,支持NavBar、TabBar、Modal等多种导航方式
3.整合React Native Navigation到项目中
因为React Native Navigation是第三方库,而且都是通过原生组件实现
,因此需要分别在Andoird项目和iOS项目里各自添加React Native Navigation的Andorid和iOS代码。
由于文档全是英文的,有些东西如果理解不到位的话,也会导致依赖搭不起来。
导入这个库的步骤还是挺复杂的,想快速使用react-native-navigation,可直接copy项目bootstrap,
地址:https://github.com/wix/react-native-navigation-bootstrap
我是自己整合到项目里的,毕竟打包的时候也需要依赖React Native Navigation这个库,具体步骤可以根据官方的文档来:
1.下载React Native Navigation包:
npm install react-native-navigation@next --save
2.首先是Android依赖:
地址:https://github.com/wix/react-native-navigation/wiki/Installation---Android
1.在android
中找到settings.gradle
,添加如下代码:
include ':react-native-navigation'
project(':react-native-navigation').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-navigation/android/app/')
2.在android/app
中找到build.gradle
,添加其依赖代码:
dependencies {
...
compile project(':react-native-navigation')//新添
}
3.在android/app/src/main/java/com/项目名
中找到MainActivity.java
,修改其继承关系,将继承的ReactActivity
替换成SplashActivity
。
修改前:
package com.zcc;
import com.facebook.react.ReactActivity;
public class MainActivity extends ReactActivity {
/**
* Returns the name of the main component registered from JavaScript.
* This is used to schedule rendering of the component.
*/
@Override
protected String getMainComponentName() {
return "AwesomeProject";
}
}
修改后:
package com.zcc;
import com.reactnativenavigation.controllers.SplashActivity;
public class MainActivity extends SplashActivity {
}
4.在android/app/src/main/java/com/项目名
中找到MainApplication.java
,同样修改其继承关系,取消接口实现。
修改前:
package com.zcc;
import android.app.Application;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;
import java.util.Arrays;
import java.util.List;
public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage()
);
}
};
@Override
public ReactNativeHost getReactNativeHost() {
return mReactNativeHost;
}
@Override
public void onCreate() {
super.onCreate();
SoLoader.init(this, /* native exopackage */ false);
}
}
修改后:
package com.zcc;
import android.app.Application;
import com.facebook.react.ReactPackage;
import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;
import java.util.Arrays;
import java.util.List;
import com.reactnativenavigation.NavigationApplication;
public class MainApplication extends NavigationApplication{
@Override
public boolean isDebug() {
// Make sure you are using BuildConfig from your own application
return BuildConfig.DEBUG;
}
@Override
public List<ReactPackage> createAdditionalReactPackages() {
// Add the packages you require here.
// No need to add RnnPackage and MainReactPackage
return null;
};
}
好了,Android的依赖总算完成,是不是很复杂,有木有!还没完,还有iOS的。
3.接着是iOS依赖
地址:https://github.com/wix/react-native-navigation/wiki/Installation---iOS
1.打开Xcode,找到Libraries
目录,鼠标点击右键,将ReactNativeNavigation.xcodeproj
项目导入到自己项目。有截图:
2.找到Build Phases
,在Link Binary With Libraries
中添加其依赖包libReactNativeNavigation.a
。有截图:
3.找到Build Settings
,在Header Search Paths
中添加如下代码:
$(SRCROOT)/../node_modules/react-native-navigation/ios
并且后边选成recursive
。
4.在项目中找到AppDelegate.m
并对其进行修改。
修改前:
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "AppDelegate.h"
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSURL *jsCodeLocation;
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:@"zcc"
initialProperties:nil
launchOptions:launchOptions];
rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
return YES;
}
@end
修改后:
#import "AppDelegate.h"
#import "RCCManager.h"
#import <React/RCTRootView.h>
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSURL *jsCodeLocation;
#ifdef DEBUG
jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"];
#else
jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.window.backgroundColor = [UIColor whiteColor];
[[RCCManager sharedInstance] initBridgeWithBundleURL:jsCodeLocation];
return YES;
}
@end
大功告成,终于可以使用这个库,是不是很复杂。
4.如何使用和注册页面
如果上面的步骤你都照做,基本上就已经成功导入了该库。接着我们看如何使用这个库。
- 统一Andoid和iOS的入口,修改
index.android.js
和index.ios.js
:
import App from './src/app';
2.在src/app.js
里面注册页面及导航,启动app:
import {
Platform
} from 'react-native';
import {Navigation} from 'react-native-navigation';
import {registerScreens} from './screens';//导入registerScreens方法
//注册整个APP需要的页面
registerScreens();
//创建Tabbar导航
const createTabs = () => {
let tabs = [
{
label: '停车',
screen: 'example.Home',
icon: require('../img/one.png'),
selectedIcon: require('../img/one_selected.png'),
title: '找停车场'
},
{
label: '精选',
screen: 'example.Read',
icon: require('../img/two.png'),
selectedIcon: require('../img/two_selected.png'),
title: '每日精选',
navigatorStyle: {
tabBarBackgroundColor: '#7E8FDA',
tabBarButtonColor: '#ffffff',
tabBarSelectedButtonColor: '#f8f8f8'
}
},
{
label: '博客',
screen: 'example.Blog',
icon: require('../img/three.png'),
selectedIcon: require('../img/three_selected.png'),
title: '个人博客',
navigatorStyle: {
tabBarBackgroundColor: '#7E8FDA',
tabBarButtonColor: '#ffffff',
tabBarSelectedButtonColor: '#f8f8f8'
}
},{
label: '设置',
screen: 'example.Setting',
icon: require('../img/four.png'),
selectedIcon: require('../img/four_selected.png'),
title: '关于信息',
navigatorStyle: {
tabBarBackgroundColor: '#7E8FDA',
tabBarButtonColor: '#ffffff',
tabBarSelectedButtonColor: '#f8f8f8'
}
}
];
return tabs;
};
//启动App
Navigation.startTabBasedApp({
tabs: createTabs(),
tabsStyle: {
tabBarButtonColor: '#7E8FDA'
},
appStyle: {
tabBarBackgroundColor: '#7E8FDA',
tabBarButtonColor: '#ffffff',
tabBarSelectedButtonColor: '#f8f8f8'
}
});
3.在src/screens
目录下添加index.android.js
及index.ios.js
,添加注册页面的代码:
import {Navigation} from 'react-native-navigation';
import Home from './home/Home';
import Read from './read/Read';
import ReadDetail from './read/readDetail/ReadDetail';
import Blog from './blog/Blog';
import Setting from './setting/Setting';
import SettingDetail from './setting/settingInfo/Detail';
import SettingHelp from './setting/settingInfo/Help';
import SettingTips from './setting/settingInfo/Tips';
import SettingAbout from './setting/settingInfo/About';
// 注册APP所有的页面 (包含子页面)
export function registerScreens() {
Navigation.registerComponent('example.Home', () => Home);
Navigation.registerComponent('example.Read', () => Read);
Navigation.registerComponent('example.ReadDetail', () => ReadDetail);
Navigation.registerComponent('example.Blog', () => Blog);
Navigation.registerComponent('example.Setting', () => Setting);
Navigation.registerComponent('example.SettingDetail', () => SettingDetail);
Navigation.registerComponent('example.SettingHelp', () => SettingHelp);
Navigation.registerComponent('example.SettingTips', () => SettingTips);
Navigation.registerComponent('example.SettingAbout', () => SettingAbout);
}
这样即可看到你配置的Tab效果。
5.常用的方法及用途
1.注册页面,并取名
Navigation.registerComponent(screenID, generator)
Navigation.registerComponent('example.FirstTabScreen', () => FirstTabScreen);
2.生成底部的Tab,通常2~5个
Navigation.startTabBasedApp(params)
Navigation.startTabBasedApp({
tabs: [
{
label: 'One', // tab label as appears under the icon in iOS (optional)
screen: 'example.FirstTabScreen', // unique ID registered with Navigation.registerScreen
icon: require('../img/one.png'), // local image asset for the tab icon unselected state (optional on iOS)
selectedIcon: require('../img/one_selected.png'), // local image asset for the tab icon selected state (optional, iOS only. On Android, Use `tabBarSelectedButtonColor` instead)
title: 'Screen One', // title of the screen as appears in the nav bar (optional)
navigatorStyle: {}, // override the navigator style for the tab screen, see "Styling the navigator" below (optional),
navigatorButtons: {} // override the nav buttons for the tab screen, see "Adding buttons to the navigator" below (optional)
},
{
label: 'Two',
screen: 'example.SecondTabScreen',
icon: require('../img/two.png'),
selectedIcon: require('../img/two_selected.png'),
title: 'Screen Two'
}
],
tabsStyle: { // optional, add this if you want to style the tab bar beyond the defaults
tabBarButtonColor: '#ffff00', // optional, change the color of the tab icons and text (also unselected)
tabBarSelectedButtonColor: '#ff9900', // optional, change the color of the selected tab icon and text (only selected)
tabBarBackgroundColor: '#551A8B' // optional, change the background color of the tab bar
},
appStyle: {
orientation: 'portrait' // Sets a specific orientation to the entire app. Default: 'auto'. Supported values: 'auto', 'landscape', 'portrait'
},
drawer: { // optional, add this if you want a side menu drawer in your app
left: { // optional, define if you want a drawer from the left
screen: 'example.FirstSideMenu' // unique ID registered with Navigation.registerScreen
},
right: { // optional, define if you want a drawer from the right
screen: 'example.SecondSideMenu' // unique ID registered with Navigation.registerScreen
},
disableOpenGesture: false // optional, can the drawer be opened with a swipe instead of button
},
passProps: {}, // simple serializable object that will pass as props to all top screens (optional)
animationType: 'slide-down' // optional, add transition animation to root change: 'none', 'slide-down', 'fade'
});
3.跳入详情页面
一般在注册页面调用this.props.navigator
可访问该属性。
push(params)
this.props.navigator.push({
screen: 'example.ScreenThree', // unique ID registered with Navigation.registerScreen
title: undefined, // navigation bar title of the pushed screen (optional)
titleImage: require('../../img/my_image.png'), //navigation bar title image instead of the title text of the pushed screen (optional)
passProps: {}, // Object that will be passed as props to the pushed screen (optional)
animated: true, // does the push have transition animation or does it happen immediately (optional)
backButtonTitle: undefined, // override the back button title (optional)
backButtonHidden: false, // hide the back button altogether (optional)
navigatorStyle: {}, // override the navigator style for the pushed screen (optional)
navigatorButtons: {} // override the nav buttons for the pushed screen (optional)
});
我在项目里面仅使用这三个API就实现了所有的页面及交互,其实使用起来特别简单,就是在整合时麻烦。
4.其他API 更多API可以去官网上看噢:https://github.com/wix/react-native-navigation/wiki/Top-Level-API 所有API列表: 顶层API Navigation
- registerComponent
- startTabBasedApp
- startSingleScreenApp
- registerScreen
页面API navigation
- push
- pop
- popToRoot
- resetTosetOnNavigatorEvent
- setButtons
- setTitle
- toggleDrawer
- toggleTabs
- setTabBadge
- switchToTab
- toggleNavBar
学完上面这个库,你可以使用React Native提供的各种组件去绘制页面啦,下一章也是最后一章将讲解React Native提供的常用组件。欢迎阅读~