一、环境搭建
1.1 React Native环境搭建
1.1.1 IOS环境搭建
环境:
MacOS
# 如果你已经安装了 Node,请检查其版本是否在 v8.3 以上
brew install node
# Watchman则是由 Facebook 提供的监视文件系统变更的工具。安装此工具可以提高开发时的性能
brew install watchman
-
注意:不要使用
cnpm!cnpm安装的模块路径比较奇怪,packager不能正常识别!
npm install -g yarn react-native-cli
1. 创建新项目
init命令默认会创建最新的版本,而目前最新的0.45及以上版本需要下载boost等几个第三方库编译。这些库在国内即便翻墙也很难下载成功,导致很多人无法运行iOS项目。可以暂时创建0.44.3的版本
react-native init MyApp --version 0.44.3
2. 编译并运行 React Native 应用
1). 运行方式一 在你的项目目录中运行react-native run-ios
cd MyApp
react-native run-ios
2). 运行方式二 在xCode中运行
打开
xcode选择项目中myApp/ios/myApp.xcodeproj,然后点击左上角运行即可
3. 远程调试
-
ctrl + R刷新 -
ctrl + D选择对应的工具调试
image.png
Enable Live Reload
当你的js代码发生变化后,
React Native会自动生成bundle然后传输到模拟器或手机上
[图片上传失败...(image-e2a80d-1565014986904)]
image.png
巧用Sources面板
[图片上传失败...(image-8618e9-1565014986904)]
指定模拟的设备类型
- 你可以使用
--simulator参数,在其后加上要使用的设备名称来指定要模拟的设备类型(目前默认为"iPhone X")。如果你要模拟iPhone 4s,那么这样运行命令即可:react-native run-ios --simulator "iPhone 4s"。 - 你可以在终端中运行
xcrun simctl list devices来查看具体可用的设备名称
image.png
1.1.2 安卓环境搭建
安装依赖
必须安装的依赖有:
Node、Watchman和React Native命令行工具以及 JDK 和Android Studio
brew install node
brew install watchman
npm install -g yarn react-native-cli
Java Development Kit
React Native需要Java Development Kit [JDK] 1.8(暂不支持1.9及更高版本)。你可以在命令行中输入
-
javac -version来查看你当前安装的JDK版本。如果版本不合要求,则可以到 官网上下载
1. 安装 Android Studio
首先下载和安装
Android Studio,国内用户可能无法打开官方链接,请自行使用搜索引擎搜索可用的下载链接。安装界面中选择"Custom"选项,确保选中了以下几项
Android SDKAndroid SDK PlatformPerformance (Intel ® HAXM)Android Virtual Device
然后点击"
Next"来安装选中的组件。安装完成后,看到欢迎界面时,就可以进行下面的操作了
2. 安装 Android SDK
Android Studio默认会安装最新版本的Android SDK。目前编译React Native应用需要的是Android 8.1 (Oreo)版本的SDK。你可以在Android Studio的SDK Manager中选择安装各版本的SDK
你可以在 Android Studio 的欢迎界面中找到 SDK Manager。点击"Configure",然后就能看到"SDK Manager"。
image
在
SDK Manager中选择"SDK Platforms"选项卡,然后在右下角勾选"Show Package Details"。展开Android 8.1 (Oreo)选项,确保勾选了下面这些组件(重申你必须使用稳定的翻墙工具,否则可能都看不到这个界面):
Android SDK Platform 27-
Intel x86 Atom_64 System Image(官方模拟器镜像文件,使用非官方模拟器不需要安装此组件)
image.png
SDK Manager还可以在Android Studio的"Preferences"菜单中找到。具体路径是Appearance & Behavior → System Settings → Android SDK
- 然后点击"
SDK Tools"选项卡,同样勾中右下角的"Show Package Details"。展开"Android SDK Build-Tools"选项,确保选中了React Native所必须的27.0.3版本。你可以同时安装多个其他版本
image.png
最后点击"
Apply"来下载和安装这些组件。
3. 配置 ANDROID_HOME 环境变量
React Native需要通过环境变量来了解你的Android SDK装在什么路径,从而正常进行编译
- 具体的做法是把下面的命令加入到
~/.bash_profile文件中
# 如果你不是通过Android Studio安装的sdk,则其路径可能不同,请自行确定清楚。
export ANDROID_HOME=$HOME/Library/Android/sdk
export PATH=$PATH:$ANDROID_HOME/tools
export PATH=$PATH:$ANDROID_HOME/tools/bin
export PATH=$PATH:$ANDROID_HOME/platform-tools
export PATH=$PATH:$ANDROID_HOME/emulator
如果你的命令行不是
bash,而是例如zsh等其他,请使用对应的配置文件
使用
source $HOME/.bash_profile命令来使环境变量设置立即生效(否则重启后才生效)。可以使用echo $ANDROID_HOME检查此变量是否已正确设置
4. 编译并运行 React Native 应用
确保你先运行了模拟器或者连接了真机,然后在你的项目目录中运行
react-native run-android
Android Studio自带工具运行
image.png
使用genymotion模拟器
去官网需要注册并下载https://www.genymotion.com/,需要注册登录再下载的。注意下载
with virtualBox版本,然后安装完成后需要登录,就是刚才注册的账号。登录后进入这个页面做两个操作
image.png
点击
settings,选择adb设置sdk就是刚才一直用的sdk安装路径,如下
image.png
启动项目,点击
genymotion里的start启动我们刚才安装好的的虚拟设备,是这个样子的,此时我们刚才初始化的项目还没连上虚拟设备
image.png
然后在我们的工程项目里执行
adb devices会列出当前启动的虚拟设备,能检测到说明没问题,如下图里最后一行显示的就是刚才我们开启的genymotion那台虚拟设备
image.png
最后项目目录里执行
react-native run-android
打开
genymotion,欢迎页面出来了,成功,修改一下文字,重新加载一遍,成功
- 第一次默认不是热加载形式,就是改变文件内容需要手动刷新的,这里设置一下热加载,以后内容这里就会自动刷新,
mac是执行command+r,选择第四个hot reloading
image.png
运行
react-native run-andriod会下载很多东西,然后出现这个标志说明编译没有问题,还缺少一个模拟设备
image.png
image.png
image.png
如果是安卓5.0以下需要配置一下IP
image.png
1.2 安卓设备真机调试
1. 开启 USB 调试
在默认情况下
Android设备只能从应用市场来安装应用。你需要开启USB调试才能自由安装开发版本的APP
2. 通过 USB 数据线连接设备
下面检查你的设备是否能正确连接到
ADB(Android Debug Bridge),使用adb devices命令:
image.png
3. 运行应用
现在你可以运行
react-native run-android来在设备上安装并启动应用了
从设备上访问开发服务器
- 运行
adb reverse tcp:8081 tcp:8081 - 在命令行执行
adb shell input keyevent 82弹出开发者工具。打开热更新和远程调试
1.3 移除vscode装饰器报错
点击
Visual Studio Code左下角的配置按钮。在搜索框内输入“experimentalDecorators”,发现竟然能够找到选项,如下
"javascript.implicitProjectConfig.experimentalDecorators": false
试着将false改为true,重启Visual Studio Code
二、矢量图标的运用
https://github.com/oblador/react-native-vector-icons
react-native-vector-icons是可以直接使用图片名就能加载图片的第三方,类似于web的 iconfont矢量图,使用很方便, 你不需要在工程文件夹里塞各种图片, 节省很多空间,下面就来看看怎么使用吧
npm install react-native-vector-icons --save
npm install rnpm -g
2.1 android平台
1. 自动配置
react-native link react-native-vector-icons
# 或者
npm install -g rnpm
rnpm link react-native-vector-icons
会为你配置好所有,但是这是成功的情况下,你不需要操心任何事,但是往往不能如愿。如果你这步成功了,而且能够正常运行,下面这些你就可以跳过
2. 手动配置
- 第一步:复制字体文件(这一步千万不能忘记,不然就算运行成功你也看不到图标)
找到项目
node_modules/react-native-vector-icons/Fonts,里面有很多已经内置的图标库字体文件,依照自己的需求,复制你需要的字体文件到android/app/src/main/assets/fonts,(如果没有这个目录就自行创建)
- 第二步:配置
android/settings.gradle
在现有的代码基础上添加如下代码
include ':react-native-vector-icons'
project(':react-native-vector-icons').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-vector-icons/android')
- 第三步:配置
android/app/build.gradle
dependencies {
compile project(':react-native-vector-icons') //添加
compile fileTree(dir: "libs", include: ["*.jar"])
compile "com.android.support:appcompat-v7:23.0.1"
compile "com.facebook.react:react-native:+" // From node_modules
compile project(':react-native-navigation')
}
- 第四步:配置
android/app/src/main/java/com/xxxx/MainApplication.java
import com.oblador.vectoricons.VectorIconsPackage;
@Override
protected List<ReactPackage> getPackages() {
return Arrays.<ReactPackage>asList(
new MainReactPackage()
+ , new VectorIconsPackage()
);
}
到这里配置就全部完成,接下来就可以在
rn项目中使用iconfont
2.2 IOS平台
打开你的
Xcode项目工程,右键工程文件,选择react项目下的node_modules/react-native-vector-icons/Fonts文件
image.png
在xcode的Info.plist文件中,加入: Fonts provided by application数组
image.png
打开终端,输入:
rnpm link,回车后会看到Fonts provided by application下加入如下字体
image.png
重新运行
react项目,终端输入:react-native run-ios,可以看到效果了
三、react-native-router-flux的使用
3.1 简介
特性
react-native-router-flux是一个路由包.在一个中心区域定义可切换scene模块。在使用过程中,跟react-native提供的navigator的区别是你不需要有navigator对象。你可以在任意地方使用简单的语法去控制scene的切换,如:Actions.login({username, password})orActions.profile({profile})or 甚至Actions.profile(123),其中loginprofile等是路由的key,通过调用key来切换路由
- 所有的参数将被注入到
this.props中给Sene组件使用
功能和亮点
- 可定制的导航条:由
Scene或者Scene的state去控制导航条的show/hide - 嵌套导航:每一个
tab都可以有自己的导航,该导航被嵌套在root导航中 - 使用
Action sheet来自定义场景渲染器 - 动态路由:动态路由将允许你通过应用的
state去选着哪个scene将被渲染 -
Reset History stack重置历史栈:新的reset类型将提供清除历史栈河消除导航的返回按钮的功能 - 更加强大的状态控制:在多个
scene中可以有不同的state
npm i react-native-router-flux --save
使用方式一
在你的
src/index.js级别的文件中使用Scene组件定义你的scenes,并且Scene组件作为Router的子节点。定义好的Scene将由Router来控制其行为
import {Scene, Router, Actions} from 'react-native-router-flux';
import {Router, Scene} from "react-native-router-flux";
import PageOne from "./Component/PageOne";
import PageTwo from "./Component/PageTwo";
const Root = () => {
return (
<Router>
{/* 这种写法是将全部的跳转页面都放在Root下面 */}
<Scene key="root">
{/* key 就是给页面的标签,供Actions使用 */}
{/* component 设置关联的页面 */}
{/* title 就是给页面标题 */}
{/* initial 就是设置默认页面*/}
<Scene
key="one"
component={PageOne}
title="PageOne"
initial={true}
/>
<Scene key="two" component={PageTwo} title="PageTwo" />
</Scene>
</Router>
);
};
第二种使用方式
你可以在编译期定义你所有的
scenes,并在后面的Router里面使用
import {Actions, Scene, Router} from 'react-native-router-flux';
const scenes = Actions.create(
<Scene key="root">
<Scene key="login" component={Login} title="Login"/>
<Scene key="register" component={Register} title="Register"/>
<Scene key="home" component={Home}/>
</Scene>
);
/* ... */
class App extends React.Component {
render() {
return <Router scenes={scenes}/>
}
}
{Actions, Scene, Router} from 'react-native-router-flux';
const scenes = Actions.create(
<Scene key="root">
<Scene key="login" component={Login} title="Login"/>
<Scene key="register" component={Register} title="Register"/>
<Scene key="home" component={Home}/>
</Scene>
);
/* ... */
class App extends React.Component {
render() {
return <Router scenes={scenes}/>
}
}
在任意地方通过导入
import {Actions} from 'react-native-router-flux'
获得
Actions对象,Actions对象将是我们操作Scenes的遥控器。通过Actions我们可以向Router发出动作让Router控制Scene变化。
- 调用
Actions.ACTION_NAME(PARAMS)可以展示一个scene,参数将被注入scene中
(如Actions.login()切换到登录页面) -
Actions.pop()方法将会弹出当前的scene,他接受如下可选参数-
{popNum:[number]}允许你去一次弹出多个scene -
{refresh:{...propsToSetOnPreviousScene}}允许你去刷新pop后的scene
-
-
Actions.refresh(PARAMS)会更新当前scene的属性
3.2 简单例子
import {Router, Scene} from "react-native-router-flux";
import PageOne from "./Component/PageOne";
import PageTwo from "./Component/PageTwo";
const Root = () => {
return (
<Router>
{/* 这种写法是将全部的跳转页面都放在Root下面 */}
<Scene key="root">
{/* key 就是给页面的标签,供Actions使用 */}
{/* component 设置关联的页面 */}
{/* title 就是给页面标题 */}
{/* initial 就是设置默认页面*/}
<Scene
key="one"
component={PageOne}
title="PageOne"
initial={true}
/>
<Scene key="two" component={PageTwo} title="PageTwo" />
</Scene>
</Router>
);
};
// PageOne 的核心代码,点击 Text 跳转到下一个页面
//导入Action的包,处理页面跳转
import { Actions } from 'react-native-router-flux';
const PageOne = () => {
return (
<View style={styles.container}>
<Text style={styles.welcome}
onPress={()=>Actions.two()} >
我是Page One
</Text>
</View>
);
};
// PageTwo 的核心代码
export default class PageTwo extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>我是Page Two </Text>
</View>)
}
}
运行就可以看到下面的效果:
image.png
简单就完成了两个页面之间的切换
每一个Scene component 有如下属性
-
key:一个唯一的字符串,用来标识一个Scene,可以理解为scene的一个身份牌号码 -
component:当切换到该scene时,component属性引用的组件将被渲染出来 -
title:当切换到对应的scene时,屏幕顶部的导航条中间将显示该title -
initial={true}表示默认为初始化scene
在
pageOne中有一个Text组件,当点击onPress方法,该方法将调用Actions.pageTwo
- 会调用
Actions.SCENE_KEY(PARAMS),SCENE_KEY即为之前定义的key值,参数为可选的 - 我们的
Actions就会通知Router,把key=pageTwo的Scene显示出来,如果传有参数的话,参数也会传入Scene组件中
render() {
const goToPageTwo = () => Actions.pageTwo({text: 'Hello World!'});
return (
This is PageOne!
)
}
我们传递一个参数名为
text。值为Hello World!如下所示,我们就可以在key=pageTwo的scene的component属性置顶的组件中通过props获取该参数值
render() {
return (
This is PageTwo!
{this.props.text}
)
}
我们从
pageOne跳转到了pageTwo,如果我们想跳回pageOne怎么办呢
- 官方提供的导航栏早已提供了一个
back icon,我们也可以通过调用Actions.pop()方法将当前scene弹出栈,我们的pageOne就在栈顶了,此时显示的就是pageOne了,如果跳回来后我们需要刷新当前scene,我们可以调用Actions.refresh(PARAMS)
数据传递与刷新
页面之间的切换自然不会缺少数据的传递,而且这个路由框架可以实时
refresh当前页面
- 先看页面之间传递数据吧,这里添加一个
PageThree
import {Actions} from "react-native-router-flux"
const PageThree = () => {
return (
<View style={styles.container}>
<Text style={styles.welcome}
//Actions.pop是退回到上一层
onPress={() => Actions.pop({
//refresh用于刷新数据
refresh: {
data: '从 three 回到 two'
}
})}>我是Page Three </Text>
</View>
);
};
PageTwo 也要修改一下代码
import {Actions} from 'react-native-router-flux'; // New code
export default class PageTwo extends Component {
render() {
const data = this.props.data || "null";
return (
<View style={styles.container}>
<Text style={styles.welcome}
//添加点击事件并传递数据到PageThree
onPress={() => Actions.three({data: "从 two 传递到 three"})}
>我是Page Two </Text>
<Text style={styles.refresh}
//展示从PageThree传回来的数据
> refresh:{data}</Text>
</View>)
}
}
最后到
Root.js添加新的Scence
const Root = () => {
return (
<Router>
//...........
<Scene key="three"
component={PageThree}
title="PageThree"/>
</Scene>
</Router>
);
};
此时运行就可以看到页面数据传递的效果了
image.png
可以看到从
PageThree回到PageTwo数据传递并刷新页面的效果,不过如果需要实时刷新当前页面呢?这时就需要使用Actions.refresh方法了
export default class PageTwo extends Component {
render() {
const data = this.props.data || "null";
return (
<View style={styles.container}>
<Text style={styles.welcome}
onPress={() => Actions.three({data: "从 two 传递到 three"})}
>我是Page Two </Text>
<Text style={styles.refresh}
onPress={() => Actions.refresh({
data: 'Changed data',
})}
> refresh:{data}</Text>
</View>)
}
}
Tab Scene
通过设置
Scene属性的Tabs可以设置Tabs。这个也开发中经常用到的页面效果
//设置tab选中时的字体颜色和标题
const TabIcon = ({focused , title}) => {
return (
<Text style={{color: focused ? 'blue' : 'black'}}>{title}</Text>
);
};
const Root = () => {
return (<Router>
{/*tabBarPosition设置tab是在top还是bottom */}
<Scene hideNavBar tabBarPosition="bottom">
<Tabs
key="tabbar"
swipeEnabled
wrap={false}
// 是否显示标签栏文字
showLabel={false}
tabBarStyle={{backgroundColor: "#eee"}}
//tab选中的颜色
activeBackgroundColor="white"
//tab没选中的颜色
inactiveBackgroundColor="red"
>
<Scene
key="one"
icon={TabIcon}
component={PageOne}
title="PageOne"
/>
<Scene
key="two"
component={PageTwo}
title="PageTwo"
icon={TabIcon}
/>
<Scene
key="three"
component={PageThree}
title="PageThree"
icon={TabIcon}
/>
</Tabs>
</Scene>
</Router>)
};
image.png
3.3 react-native-router-flux之API
英文版:https://github.com/aksonov/react-native-router-flux/blob/master/docs/API.md
3.3.1 Router
| Property | Type | Default | Description |
|---|---|---|---|
children |
required |
页面根组件 | |
wrapBy |
Function |
允许集成诸如Redux(connect)和Mobx(observer)之类的状态管理方案 |
|
sceneStyle |
Style |
适用于所有场景的Style(可选) |
|
backAndroidHandler |
Function |
允许在Android中自定义控制返回按钮(可选) |
backAndroidHandler用法
const onBackPress = () => {
if (Actions.state.index !== 0) {
return false
}
Actions.pop()
return true
}
backAndroidHandler={onBackPress}
3.3.2 Scene
此路由器的最重要的组件, 所有
<Scene>组件必须要有一个唯一的key。父节点<Scene>不能将component作为prop,因为它将作为其子节点的组件
| Property | Type | Default | Description |
|---|---|---|---|
key |
string |
required |
将用于标识页面,例如Actions.name(params)。必须是独一无二的 |
path |
string |
将被用来匹配传入的深层链接和传递参数,例如:/user/:id/将从/user/1234/用params {id:1234}调用场景的操作。接受uri的模板标准 |
|
component |
React.Component |
semi-required |
要显示的组件,定义嵌套时不需要Scene。 |
back |
boolean |
false |
如果是true,则显示后退按钮,而不是由上层容器定义的左侧/drawer按钮 |
backButtonImage |
string |
设置返回按钮的图片 | |
backButtonTintColor |
string |
自定义后退按钮色调 | |
init |
boolean |
false |
如果是true后退按钮不会显示 |
clone |
boolean |
false |
标有clone的场景将被视为模板,并在被推送时克隆到当前场景的父节点中 |
contentComponent |
React.Component |
用于呈现抽屉内容的组件(例如导航) | |
drawer |
boolean |
false |
载入DrawerNavigator内的子页面 |
failure |
Function |
如果on返回一个“falsey”值,那么failure将被调用 |
|
backTitle |
string |
指定场景的后退按钮标题 | |
backButtonTextStyle |
Style |
用于返回按钮文本的样式 | |
rightTitle |
string |
为场景指定右侧的按钮标题 | |
headerMode |
string |
float |
指定标题应该如何呈现:(float渲染单个标题,保持在顶部,动画随着屏幕的变化,这是iOS上的常见样式。)screen(每个屏幕都有一个标题,并且标题淡入,与屏幕一起出现,这是Android上的常见模式)如果为none(不会显示标题) |
hideNavBar |
boolean |
false |
隐藏导航栏 |
hideTabBar |
boolean |
false |
隐藏标签栏(仅适用于拥有tabs指定的场景) |
hideBackImage |
boolean |
false |
隐藏返回图片 |
initial |
boolean |
false |
设置为true后,会默认显示该页面 |
leftButtonImage |
Image |
替换左侧按钮图片 | |
leftButtonTextStyle |
Style |
左侧按钮的文字样式 | |
leftButtonStyle |
Style |
左侧按钮的样式 | |
leftButtonIconStyle |
Style |
左侧按钮的图标样式 | |
modal |
boolean |
false |
将场景容器定义为modal,即所有子场景都将从底部弹起到顶部。它仅适用于containers(与v3版本的语法不同) |
navBar |
React.Component |
可以使用自定义的React组件来定义导航栏 |
|
navBarButtonColor |
string |
设置导航栏返回按钮的颜色 | |
navigationBarStyle |
Style |
导航栏的样式 | |
navigationBarTitleImage |
Object |
导航栏中的图像中覆盖title的Image
|
|
navigationBarTitleImageStyle |
object |
navigationBarTitleImage的样式 |
|
navTransparent |
boolean |
false |
导航栏是否透明 |
on |
Function |
又名 onEnter
|
|
onEnter |
Function |
当Scene要被跳转时调用。props将被作为参数提供。只支持定义了component的场景。 |
|
onExit |
Function |
当Scene要跳转离开时调用。只支持定义了component的场景 |
|
onLeft |
Function |
当导航栏左侧按钮被点击时调用 | |
onRight |
Function |
当导航栏右侧按钮被点击时调用 | |
renderTitle |
React.Component |
使用React组件显示导航栏的title
|
|
renderLeftButton |
React.Component |
使用React组件显示导航栏的左侧按钮 |
|
renderRightButton |
React.Component |
使用React组件显示导航栏的右侧按钮 |
|
renderBackButton |
React.Component |
使用React组件显示导航栏的返回按钮 |
|
rightButtonTextStyle |
Style |
右侧按钮文字的样式 | |
success |
Function |
如on返回一个"真实"的值,那么success将被调用 |
|
tabs |
boolean |
false |
将子场景加载为TabNavigator。其他标签导航器属性也是适用 |
title |
string |
要显示在导航栏中心的文本 | |
titleStyle |
Style |
title的样式 |
|
type |
string |
push |
可选的导航操作。你可以使用replace来替换此场景中的当前场景 |
3.3.3 Tabs (<Tabs> or <Scene tabs>)
标签栏组件
你可以使用
<Scene>中的所有props来作为<Tabs>的属性。 如果要使用该组件需要设置<Scene tabs={true}>
| Property | Type | Default | Description |
|---|---|---|---|
wrap |
boolean |
true |
自动使用自己的导航栏包装每个场景(如果不是另一个容器)。 |
activeBackgroundColor |
string |
指定焦点的选项卡的选中背景颜色 | |
activeTintColor |
string |
指定标签栏图标的选中色调颜色 | |
inactiveBackgroundColor |
string |
指定非焦点的选项卡的未选中背景颜色 | |
inactiveTintColor |
string |
指定标签栏图标的未选中色调颜色 | |
labelStyle |
object |
设置tabbar上文字的样式 |
|
lazy |
boolean |
false |
在选项卡处于活动状态之前,不会渲染选项卡场景(推荐设置成true) |
tabBarComponent |
React.Component |
使用React组件以自定义标签栏 |
|
tabBarPosition |
string |
指定标签栏位置。iOS上默认为bottom,安卓上是top
|
|
tabBarStyle |
object |
标签栏样式 | |
tabStyle |
object |
单个选项卡的样式 | |
showLabel |
boolean |
true |
是否显示标签栏文字 |
swipeEnabled |
boolean |
true` | 是否可以滑动选项卡 |
animationEnabled |
boolean |
true |
切换动画 |
tabBarOnPress |
function |
自定义tabbar点击事件 |
|
backToInitial |
boolean |
false |
如果选项卡图标被点击,返回到默认选项卡 |
3.3.4 Stack (<Stack>)
将场景组合在一起的组件,用于自己的基于堆栈实现的导航。使用它将为此堆栈创建一个单独的
navigator,因此,除非您添加hideNavBar,否则将会出现两个导航条
3.3.5 Tab Scene (child <Scene> within Tabs)
用于实现
Tabs的效果展示,可以自定义icon和label
| Property | Type | Default | Description |
|---|---|---|---|
icon |
component |
undefined |
作为选项卡图标放置的RN组件 |
tabBarLabel |
string |
tabbar上的文字 |
3.3.6 Drawer (<Drawer> or <Scene drawer>)
用于实现抽屉的效果,如果要使用该组件需要设置
<drawer tabs={true}>。
| Property | Type | Default | Description |
|---|---|---|---|
drawerImage |
Image |
替换抽屉hamburger图标,你必须把它与drawer一起设置 |
|
drawerIcon |
React.Component |
用于抽屉hamburger图标的任意组件,您必须将其与drawer道具一起设置 |
|
hideDrawerButton |
boolean |
false |
是否显示drawerImage或者drawerIcon
|
drawerPosition |
string |
抽屉是在右边还是左边。可选属性right或left
|
|
drawerWidth |
number |
抽屉的宽度(以像素为单位)(可选) |
3.3.7 Modals (<Modal> or <Scene modal>)
想要实现模态,您必须将其
<Modal>作为您Router的根场景。在Modal将正常呈现第一个场景(应该是你真正的根场景),它将渲染第一个元素作为正常场景,其他所有元素作为弹出窗口(当它们 被push)
示例:在下面的示例中,root场景嵌套在<Modal>中,因为它是第一个嵌套Scene,所以它将正常呈现。如果要push到statusModal,errorModal或者loginModal,他们将呈现为Modal,默认情况下会从屏幕底部向上弹出。重要的是要注意,目前Modal不允许透明的背景。
//... import components
<Router>
<Modal>
<Scene key="root">
<Scene key="screen1" initial={true} component={Screen1} />
<Scene key="screen2" component={Screen2} />
</Scene>
<Scene key="statusModal" component={StatusModal} />
<Scene key="errorModal" component={ErrorModal} />
<Scene key="loginModal" component={LoginModal} />
</Modal>
</Router>
3.3.8 Lightbox (<Lightbox>)
Lightbox是用于将组件渲染在当前组件上Scene的组件 。与Modal不同,它将允许调整大小和背景的透明度
在下面的示例中,root场景嵌套在中<Lightbox>,因为它是第一个嵌套Scene,所以它将正常呈现。如果要push到loginLightbox,他们将呈现为Lightbox,默认情况下将放置在当前场景的顶部,允许透明的背景
//... import components
<Router>
<Lightbox>
<Scene key="root">
<Scene key="screen1" initial={true} component={Screen1} />
<Scene key="screen2" component={Screen2} />
</Scene>
{/* Lightbox components will lay over the screen, allowing transparency*/}
<Scene key="loginLightbox" component={loginLightbox} />
</Lightbox>
</Router>
3.3.9 Actions
- 该对象的主要工具是为您的应用程序提供导航功能。 假设您的
Router和Scenes配置正确,请使用下列属性在场景之间导航。 有些提供添加的功能,将React道具传递到导航场景 - 这些可以直接使用,例如,
Actions.pop()将在源代码中实现的操作,或者,您可以在场景类型中设置这些常量,当您执行Actions.main()时,它将根据您的场景类型或默认值来执行动作
| Property | Type | Default | Description |
|---|---|---|---|
[key] |
Function |
Object |
Actions将'自动'使用路由器中的场景key进行导航。如果需要跳转页面,可以直接使用Actions.key()或Actions[key].call()
|
currentScene |
String |
返回当前活动的场景 | |
jump |
Function |
(sceneKey: String, props: Object) |
用于切换到新选项卡. For Tabs only. |
popTo |
Function |
(sceneKey: String, props: Object) |
返回到指定的页面 |
push |
Function |
(sceneKey: String, props: Object) |
跳转到新页面 |
refresh |
Function |
(props: Object) |
重新加载当前页面 |
replace |
Function |
(sceneKey: String, props: Object) |
从堆栈中弹出当前场景,并将新场景推送到导航堆栈。没有过度动画 |
reset |
Function |
(sceneKey: String, props: Object) |
清除路由堆栈并将场景推入第一个索引. 没有过渡动画 |
drawerOpen |
Function |
如果可用,打开Drawer
|
|
drawerClose |
Function |
如果可用,关闭Drawer
|
3.3.10 ActionConst
键入常量以确定
Scene转换,这些是优先于手动键入其值,因为项目更新时可能会发生更改
| Property | Type | Default | Description |
|---|---|---|---|
ActionConst.JUMP |
string |
'REACT_NATIVE_ROUTER_FLUX_JUMP' |
jump |
ActionConst.PUSH |
string |
'REACT_NATIVE_ROUTER_FLUX_PUSH' |
`push |
ActionConst.PUSH_OR_POP |
string |
'REACT_NATIVE_ROUTER_FLUX_PUSH_OR_POP' |
push |
ActionConst.REPLACE |
string |
'REACT_NATIVE_ROUTER_FLUX_REPLACE' |
replace |
ActionConst.BACK |
string |
'REACT_NATIVE_ROUTER_FLUX_BACK' |
pop |
ActionConst.BACK_ACTION |
string |
'REACT_NATIVE_ROUTER_FLUX_BACK_ACTION' |
pop |
ActionConst.POP_TO |
string |
'REACT_NATIVE_ROUTER_FLUX_POP_TO' |
popTo |
ActionConst.REFRESH |
string |
'REACT_NATIVE_ROUTER_FLUX_REFRESH' |
refresh |
ActionConst.RESET |
string |
'REACT_NATIVE_ROUTER_FLUX_RESET' |
reset |
ActionConst.FOCUS |
string |
'REACT_NATIVE_ROUTER_FLUX_FOCUS' |
N/A |
ActionConst.BLUR |
string |
'REACT_NATIVE_ROUTER_FLUX_BLUR' |
N/A |
ActionConst.ANDROID_BACK |
string |
'REACT_NATIVE_ROUTER_FLUX_ANDROID_BACK' |
N/A |
3.3.11 Universal and Deep Linking
- 考虑这样一个
web应用程序和app配对,这可能有一个urlhttps://thesocialnetwork.com/profile/1234/ - 如果我们同时构建一个
web应用程序和一个移动应用程序,我们希望能够通过path /profile/:id/ - 在web上,我们可能想要用一个路由器来打开我们的
<Profile />和参数{ id: 1234 } - 在移动设备上,如果我们正确地设置了
Android / iOS环境来启动我们的应用程序并打开RNRF<Router />,,那么我们还需要导航到我们的移动<Profile />场景和参数{ id: 1234 }
<Router uriPrefix={'thesocialnetwork.com'}>
<Scene key="root">
<Scene key={'home'} component={Home} />
<Scene key={'profile'} path={"/profile/:id/"} component={Profile} />
<Scene key={'profileForm'} path={"/edit/profile/:id/"} component={ProfileForm} />
</Scene>
</Router>
如果用户点击
http://thesocialnetwork.com/profile/1234/在他们的设备,他们会打开<Router/ >,然后调用操作Actions.profile({ id:1234 })
四、React Native基础知识
4.1 常见组件
-
Image图片 -
Text文本 -
View包裹最外层
4.2 样式
实际开发中组件的样式会越来越复杂,我们建议使用
StyleSheet.create来集中定义组件的样式
import React, { Component } from 'react';
import { AppRegistry, StyleSheet, Text, View } from 'react-native';
export default class LotsOfStyles extends Component {
render() {
return (
<View>
<Text style={styles.red}>just red</Text>
<Text style={styles.bigblue}>just bigblue</Text>
<Text style={[styles.bigblue, styles.red]}>bigblue, then red</Text>
<Text style={[styles.red, styles.bigblue]}>red, then bigblue</Text>
</View>
);
}
}
const styles = StyleSheet.create({
bigblue: {
color: 'blue',
fontWeight: 'bold',
fontSize: 30,
},
red: {
color: 'red',
},
});
AppRegistry.registerComponent('LotsOfStyles', () => LotsOfStyles);
常见的做法是按顺序声明和使用
style属性,以借鉴CSS中的“层叠”做法(即后声明的属性会覆盖先声明的同名属性)
4.3 高度与宽度
最简单的给组件设定尺寸的方式就是在样式中指定固定的
width和height。React Native中的尺寸都是无单位的,表示的是与设备像素密度无关的逻辑像素点
import React, { Component } from 'react';
import { AppRegistry, View } from 'react-native';
class FixedDimensionsBasics extends Component {
render() {
return (
<View>
<View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} />
<View style={{width: 100, height: 100, backgroundColor: 'skyblue'}} />
<View style={{width: 150, height: 150, backgroundColor: 'steelblue'}} />
</View>
);
}
};
// 注册应用(registerComponent)后才能正确渲染
// 注意:只把应用作为一个整体注册一次,而不是每个组件/模块都注册
AppRegistry.registerComponent('AwesomeProject', () => FixedDimensionsBasics);
- 在组件样式中使用
flex可以使其在可利用的空间中动态地扩张或收缩。一般而言我们会使用flex:1来指定某个组件扩张以撑满所有剩余的空间。如果有多个并列的子组件使用了flex:1,则这些子组件会平分父容器中剩余的空间。如果这些并列的子组件的flex值不一样,则谁的值更大,谁占据剩余空间的比例就更大(即占据剩余空间的比等于并列组件间flex值的比) - 组件能够撑满剩余空间的前提是其父容器的尺寸不为零。如果父容器既没有固定的
width和height,也没有设定flex,则父容器的尺寸为零。其子组件如果使用了flex,也是无法显示的。
import React, { Component } from 'react';
import { AppRegistry, View } from 'react-native';
class FlexDimensionsBasics extends Component {
render() {
return (
// 试试去掉父View中的`flex: 1`。
// 则父View不再具有尺寸,因此子组件也无法再撑开。
// 然后再用`height: 300`来代替父View的`flex: 1`试试看?
<View style={{flex: 1}}>
<View style={{flex: 1, backgroundColor: 'powderblue'}} />
<View style={{flex: 2, backgroundColor: 'skyblue'}} />
<View style={{flex: 3, backgroundColor: 'steelblue'}} />
</View>
);
}
};
AppRegistry.registerComponent('AwesomeProject', () => FlexDimensionsBasics);
4.4 处理文本输入
TextInput是一个允许用户输入文本的基础组件。它有一个名为onChangeText的属性,此属性接受一个函数,而此函数会在文本变化时被调用。另外还有一个名为onSubmitEditing的属性,会在文本被提交后(用户按下软键盘上的提交键)调用
import React, { Component } from 'react';
import { AppRegistry, Text, TextInput, View } from 'react-native';
export default class PizzaTranslator extends Component {
constructor(props) {
super(props);
this.state = {text: ''};
}
render() {
return (
<View style={{padding: 10}}>
<TextInput
style={{height: 40}}
placeholder="Type here to translate!"
onChangeText={(text) => this.setState({text})}
/>
<Text style={{padding: 10, fontSize: 42}}>
{this.state.text.split(' ').map((word) => word && '🍕').join(' ')}
</Text>
</View>
);
}
}
4.5 如何使用滚动视图
ScrollView是一个通用的可滚动的容器,你可以在其中放入多个组件和视图,而且这些组件并不需要是同类型的。ScrollView不仅可以垂直滚动,还能水平滚动(通过horizontal属性来设置)
-
ScrollView适合用来显示数量不多的滚动元素。放置在ScollView中的所有组件都会被渲染,哪怕有些组件因为内容太长被挤出了屏幕外。如果你需要显示较长的滚动列表,那么应该使用功能差不多但性能更好的ListView组件
import React, { Component } from 'react';
import{ ScrollView, Image, Text, View } from 'react-native'
export default class IScrolledDownAndWhatHappenedNextShockedMe extends Component {
render() {
return(
<ScrollView>
<Text style={{fontSize:96}}>Scroll me plz</Text>
<Image source={require('./img/favicon.png')} />
<Image source={require('./img/favicon.png')} />
<Image source={require('./img/favicon.png')} />
</ScrollView>
);
}
}
4.6 如何使用长列表
-
FlatList组件用于显示一个垂直的滚动列表,其中的元素之间结构近似而仅数据不同 -
FlatList更适于长列表数据,且元素个数可以增删。和ScrollView不同的是,FlatList并不立即渲染所有元素,而是优先渲染屏幕上可见的元素 -
FlatList组件必须的两个属性是data和renderItem。data是列表的数据源,而renderItem则从数据源中逐个解析数据,然后返回一个设定好格式的组件来渲染
import React, { Component } from 'react';
import { FlatList, StyleSheet, Text, View } from 'react-native';
export default class FlatListBasics extends Component {
render() {
return (
<View style={styles.container}>
<FlatList
data={[
{key: 'Devin'},
{key: 'Jackson'},
{key: 'James'},
{key: 'Joel'},
{key: 'John'},
{key: 'Jillian'},
{key: 'Jimmy'},
{key: 'Julie'},
]}
renderItem={({item}) => <Text style={styles.item}>{item.key}</Text>}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 22
},
item: {
padding: 10,
fontSize: 18,
height: 44,
},
})
4.7 网络
默认情况下,
iOS会阻止所有非https的请求。如果你请求的接口是http协议,那么首先需要添加一个App Transport Security的例外
五、React Native布局
5.1 宽和高
- 一个组件的高度和宽度决定了它在屏幕上的尺寸,也就是大小
- 在
React Native中尺寸是没有单位的,它代表了设备独立像素
<View style={ {width:100,height:100,margin:40,backgroundColor:'gray'}}>
<Text style={ {fontSize:16,margin:20}}>尺寸</Text>
</View>
5.2 和web中的差异
React Native中的FlexBox和Web CSSS上FlexBox的不同之处
-
flexDirection:React Native中默认为flexDirection:'column',在Web CSS中默认为flex-direction:'row' -
alignItems:React Native中默认为alignItems:'stretch',在Web CSS中默认align-items:'flex-start' -
flex: 相比Web CSS的flex接受多参数,如:flex: 2 2 10%;,但在React Native中flex只接受一个参数 - 不支持属性:
align-content,flex-basis,order,flex-basis,flex-flow,flex-grow,flex-shrink
5.3 Layout
以下属性是
React Native所支持的Flex属性
5.3.1 容器属性
-
flexDirection:rowcolumnrow-reversecolumn-reverse -
flexWrap:wrapnowrap -
justifyContent:flex-startflex-endcenterspace-betweenspace-around -
alignItems:flex-startflex-endcenterstretch
5.3.2 横轴和竖轴
主轴即水平方向的轴线,可以理解成横轴,侧轴垂直于主轴,可以理解为竖轴
image
5.3.3 flexDirection
flexDirection:rowcolumnrow-reversecolumn-reverseflexDirection属性定义了父视图中的子元素沿横轴或侧轴方片的排列方式
-
row: 从左向右依次排列 -
row-reverse: 从右向左依次排列 -
column(default): 默认的排列方式,从上向下排列 -
column-reverse: 从下向上排列
<View style={ {flexDirection:'row-reverse',backgroundColor:"darkgray",marginTop:20}}>
<View style={ {width:40,height:40,backgroundColor:"darkcyan",margin:5}}>
<Text style={ {fontSize:16}}>1</Text>
</View>
<View style={ {width:40,height:40,backgroundColor:"darkcyan",margin:5}}>
<Text style={ {fontSize:16}}>2</Text>
</View>
<View style={ {width:40,height:40,backgroundColor:"darkcyan",margin:5}}>
<Text style={ {fontSize:16}}>3</Text>
</View>
<View style={ {width:40,height:40,backgroundColor:"darkcyan",margin:5}}>
<Text style={ {fontSize:16}}>4</Text>
</View>
</View>
image
5.3.4 flexWrap
flexWrap属性定义了子元素在父视图内是否允许多行排列,默认为nowrap
-
nowrap flex的元素只排列在一行上,可能导致溢出 -
wrap flex的元素在一行排列不下时,就进行多行排列
<View style={ {flexWrap:'wrap',flexDirection:'row',backgroundColor:"darkgray",marginTop:20}}>
</View>
image
5.3.5 justifyContent
justifyContent属性定义了浏览器如何分配顺着父容器主轴的弹性(flex)元素之间及其周围的空间,默认为flex-startjustifyContent:flex-startflex-endcenterspace-betweenspace-around
-
flex-start(default)从行首开始排列。每行第一个弹性元素与行首对齐,同时所有后续的弹性元素与前一个对齐 -
flex-end从行尾开始排列。每行最后一个弹性元素与行尾对齐,其他元素将与后一个对齐。 -
center伸缩元素向每行中点排列。每行第一个元素到行首的距离将与每行最后一个元素到行尾的距离相同。 -
space-between在每行上均匀分配弹性元素。相邻元素间距离相同。每行第一个元素与行首对齐,每行最后一个元素与行尾对齐。 -
space-around在每行上均匀分配弹性元素。相邻元素间距离相同。每行第一个元素到行首的距离和每行最后一个元素到行尾的距离将会是相邻元素之间距离的一半。
<View style={ {justifyContent:'center',flexDirection:'row',backgroundColor:"darkgray",marginTop:20}}>
</View>
[图片上传失败...(image-3f1462-1565014986905)]
5.3.6 alignItems
alignItems属性以与justify-content相同的方式在侧轴方向上将当前行上的弹性元素对齐,默认为stretch。
-
flex-start元素向侧轴起点对齐。 -
flex-end元素向侧轴终点对齐。 -
center元素在侧轴居中。如果元素在侧轴上的高度高于其容器,那么在两个方向上溢出距离相同。 -
stretch弹性元素被在侧轴方向被拉伸到与容器相同的高度或宽度
<View style={ {justifyContent:'center',flexDirection:'row',backgroundColor:"darkgray",marginTop:20}}>
</View>
image
5.3.7 alignSelf
alignSelf属性以属性定义了flex容器内被选中项目的对齐方式。注意:alignSelf属性可重写灵活容器的alignItems属性
-
stretch元素被拉伸以适应容器。 -
center元素位于容器的中心。 -
flex-start元素位于容器的开头。 -
flex-end元素位于容器的结尾
<View style={ {alignSelf:'baseline',width:60,height: 20,backgroundColor:"darkcyan",margin:5}}>
<Text style={ {fontSize:16}}>1</Text>
</View>
image
5.3.8 flex
flex属性定义了一个可伸缩元素的能力,默认为0
<View style={ {flexDirection:'row',height:40, backgroundColor:"darkgray",marginTop:20}}>
<View style={ {flex:1,backgroundColor:"darkcyan",margin:5}}>
<Text style={ {fontSize:16}}>flex:1</Text>
</View>
<View style={ {flex:2,backgroundColor:"darkcyan",margin:5}}>
<Text style={ {fontSize:16}}>flex:2</Text>
</View>
<View style={ {flex:3,backgroundColor:"darkcyan",margin:5}}>
<Text style={ {fontSize:16}}>flex:3</Text>
</View>
</View>
[图片上传失败...(image-459c64-1565014986905)]
5.4 视图边框
-
borderBottomWidth number底部边框宽度 -
borderLeftWidth number左边框宽度 -
borderRightWidth number右边框宽度 -
borderTopWidth number顶部边框宽度 -
borderWidth number边框宽度 -
border<Bottom|Left|Right|Top>Color个方向边框的颜色 -
borderColor边框颜色
5.5 尺寸
width numberheight number
5.6 外边距
-
margin number外边距 -
marginBottom number下外边距 -
marginHorizontal number左右外边距 -
marginLeft number左外边距 -
marginRight number右外边距 -
marginTop number上外边距 -
marginVertical number上下外边距
5.7 内边距
-
padding number内边距 -
paddingBottom number下内边距 -
paddingHorizontal number左右内边距 -
paddingLeft number做内边距 -
paddingRight number右内边距 -
paddingTop number上内边距 -
paddingVertical number上下内边距
5.8 边缘
-
left number属性规定元素的左边缘。该属性定义了定位元素左外边距边界与其包含块左边界之间的偏移。 -
right number属性规定元素的右边缘。该属性定义了定位元素右外边距边界与其包含块右边界之间的偏移 -
top number属性规定元素的顶部边缘。该属性定义了一个定位元素的上外边距边界与其包含块上边界之间的偏移。 -
bottom number属性规定元素的底部边缘。该属性定义了一个定位元素的下外边距边界与其包含块下边界之间的偏移。
5.9 定位(position)
position:absolute|relative属性设置元素的定位方式,为将要定位的元素定义定位规则。
-
absolute:生成绝对定位的元素,元素的位置通过 "left", "top", "right" 以及 "bottom" 属性进行规定。 -
relative:生成相对定位的元素,相对于其正常位置进行定位。因此,"left:20" 会向元素的LEFT位置添加20像素。
六、React Native适配
6.1 Platform.OS
为了提高代码的兼容性,我们有时需要判断当前系统的平台,然后做一些适配。比如,我们在使用
StatusBar做导航栏的时候,在iOS平台下根视图的位置默认情况下是占据状态栏的位置的,我们通常希望状态栏下面能显示一个导航栏,所以我们需要为StatusBar的外部容器设置一个高度
<View style={{height: Platform.OS === 'ios' ? 20:0}}>
<StatusBar {...this.props.statusBar} />
</View>;
6.2 留意api doc的android或ios标识
并不是所有
React Native的一些api或组件的一些属性和方法都兼容Android和iOS,在React Native的api doc中通常会在一些属性或方法的前面加上android或ios的字样来标识该属性或方法所支持的平台,如
android renderToHardwareTextureAndroid bool
ios shouldRasterizeIOS bool
在上述代码中,
renderToHardwareTextureAndroid bool只支持Android平台,ios shouldRasterizeIOS bool只支持iOS平台,所有我们在使用这些带有标记的属性或方法的时候就需要考虑对于它们不兼容的平台我们是否需要做相应的适配了
6.3 组件选择
比如,我们要开发一款应用需要用到导航组件,
在React Native组件中有NavigatorIOS与Navigator两个导航组件来供我们选择,从api doc中我们可以看出NavigatorIOS只支持iOS平台,Navigator则两个平台都支持。
所以如果我们要开发的应用需要适配Android和iOS,那么Navigator才是最佳的选择。
为了提高代码的复用性与兼容性建议大家在选择React Native组件的时候要多留意该组件是不是兼容Android和iOS,尽量选择Android和iOS平台都兼容的组件。
6.4 图片适配
开发一款应用少不了的需要用到图标。无论是
Android还是iOS,现在不同分辨率的设备越来越多,我们希望这些图标能够适配不同分辨率的设备。为此我们需要为每个图标提供1x、2x、3x三种大小的尺寸,React Native会根据屏幕的分辨率来动态的选择显示不同尺寸的图片。比如:在img目录下有如下三种尺寸的check.png
└── img
├── check.png
├── check@2x.png
└── check@3x.png
那么我们就可以通过下面的方式来使用check.png
<Image source={require('./img/check.png')} />
提示:我们在使用具有不同分辨率的图标时,一定要引用标准分辨率的图片如
require('./img/check.png'),如果我们这样写require('./img/check@2x.png'),那么应用在不同分辨率的设备上都只会显示check@2x.png图片,也就无法达到图片自适配的效果。
七、react-navigation
文档 https://reactnavigation.org/docs/zh-Hans/getting-started.html
7.1 页面切换
- 跳转到新的页面(将新路由推送到堆栈导航器,如果它尚未在堆栈中,则跳转到该页面)
this.props.navigation.navigate('Details',{}) - 不考虑现有导航历史的情况下添加其他路由
this.props.navigation.push - 返回
this.props.navigation.goBack() - 返回到堆栈中的第一个页面
navigation.popToTop()
7.2 传递参数给路由
-
navigate接受可选的第二个参数,以便将参数传递给要导航到的路由。 例如:this.props.navigation.navigate('RouteName', {paramName: 'value'})。 - 我们可以使用
this.props.navigation.getParam读取参数 - 你也可以使用
this.props.navigation.state.params作为getParam的替代方案, 如果未指定参数,它的值是null
/* 1. Navigate to the Details route with params */
this.props.navigation.navigate('Details', {
itemId: 86,
otherParam: 'anything you want here',
});
/* 2. Get the param, provide a fallback value if not available */
const { navigation } = this.props;
const itemId = navigation.getParam('itemId', 'NO-ID');
const otherParam = navigation.getParam('otherParam', 'some default value');
7.3 配置标题栏
每个页面组件可以有一个名为
navigationOptions的静态属性,它是一个对象或一个返回包含各种配置选项的对象的函数。我们用于设置标题栏的标题的是title这个属性,如以下示例所示
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Home',
};
/* render function, etc */
}
class DetailsScreen extends React.Component {
static navigationOptions = {
title: 'Details',
};
/* render function, etc */
}
createStackNavigator默认情况下按照平台惯例设置,所以在iOS上标题居中,在Android上左对齐
7.3.1 动态设置标题
class DetailsScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
title: navigation.getParam('otherParam', 'A Nested Details Screen'),
};
};
/* render function, etc */
}
7.3.2 使用setParams更新navigationOptions
通常有必要从已加载的页面组件本身更新当前页面的
navigationOptions配置。 我们可以使用this.props.navigation.setParams来做到这一点
/* Inside of render() */
<Button
title="Update the title"
onPress={() => this.props.navigation.setParams({otherParam: 'Updated!'})}
/>
7.3.3 调整标题样式
定制标题样式时有三个关键属性:headerStyle、headerTintColor和headerTitleStyle
-
headerStyle:一个应用于header的最外层View的 样式对象, 如果你设置backgroundColor,他就是header的颜色 -
headerTintColor:返回按钮和标题都使用这个属性作为它们的颜色。 在下面的例子中,我们将tint color设置为白色(#fff),所以返回按钮和标题栏标题将变为白色 -
headerTitleStyle:如果我们想为标题定制fontFamily,fontWeight和其他Text样式属性,我们可以用它来完成。
class HomeScreen extends React.Component {
static navigationOptions = {
title: 'Home',
headerStyle: {
backgroundColor: '#f4511e',
},
headerTintColor: '#fff',
headerTitleStyle: {
fontWeight: 'bold',
},
};
/* render function, etc */
}
7.3.4 统一配置所有页面头部defaultNavigationOptions
在初始化时,还可以在
stack navigator的配置中指定共享的navigationOptions静态属性优先于该配置
const Home = createStackNavigator(
{
Feed: ExampleScreen,
Profile: ExampleScreen,
}, {
defaultNavigationOptions: {
headerTintColor: '#fff',
headerStyle: {
backgroundColor: '#000',
},
},
navigationOptions: {
tabBarLabel: 'Home!',
},
}
);
7.3.5 覆盖共享的navigationOptions
class DetailsScreen extends React.Component {
static navigationOptions = ({ navigation, navigationOptions }) => {
const { params } = navigation.state;
return {
title: params ? params.otherParam : 'A Nested Details Screen',
/* These values are used instead of the shared configuration! */
headerStyle: {
backgroundColor: navigationOptions.headerTintColor,
},
headerTintColor: navigationOptions.headerStyle.backgroundColor,
};
};
/* render function, etc */
}
7.4 标题栏和其所属的页面之间的交互
class HomeScreen extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
headerTitle: <LogoTitle />,
headerRight: (
<Button
onPress={navigation.getParam('increaseCount')} //执行事件
title="+1"
color="#fff"
/>
),
};
};
componentDidMount() {
// 设置事件
this.props.navigation.setParams({ increaseCount: this._increaseCount });
}
state = {
count: 0,
};
_increaseCount = () => {
this.setState({ count: this.state.count + 1 });
};
/* later in the render function we display the count */
}
八、打包
8.1 修改app名称、logo、启动图
修改图标和名称
找到根目录
/android/app/src/main/res
image.png
启动页
- 在
react-native的android中的启动图和IOS不相同点在于,android没有默认的启动图,在IOS里面有- 使用插件
import SplashScreen from 'react-native-splash-screen';- https://github.com/crazycodeboy/react-native-splash-screen
image.png
react-native ios端icon和启动图的设置
8.2 Android打包APK
1. 在Android/app目录下执行这条命令
keytool -genkey -v -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000
image.png
MYAPP_RELEASE_STORE_FILE=my-release-key.keystore
MYAPP_RELEASE_KEY_ALIAS=my-key-alias
MYAPP_RELEASE_STORE_PASSWORD=123456
MYAPP_RELEASE_KEY_PASSWORD=123456
2. 在app/build.gradle中配置
signingConfigs {
release {
if (project.hasProperty('MYAPP_RELEASE_STORE_FILE')) {
storeFile file(MYAPP_RELEASE_STORE_FILE)
storePassword MYAPP_RELEASE_STORE_PASSWORD
keyAlias MYAPP_RELEASE_KEY_ALIAS
keyPassword MYAPP_RELEASE_KEY_PASSWORD
}
}
}
buildTypes {
release {
minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
signingConfig signingConfigs.release
}
}
image.png
3. 减少打包apk大小
image.png
4. 输出目录
android/app/build/outputs/apk/
8.3 IOS打包
九、更多参考
- 常用的react-native组件整理
- React Native 研究与实践
- 从navigator到react-navigation进阶教程
- React Native0.50+开发指导
- React Native 集成分享第三方登录功能分享第三方登录模块开发(iOS)
- React Native 集成分享第三方登录功能分享第三方登录模块开发(Android)
- 教你轻松在React Native中集成统计的功能
- 教你轻松修改React Native端口
- React Native Android iOS 教程快速创建React Native App
- Mac(OSX)平台搭建React Native开发环境














网友评论