React Native学习之适配Android/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
,然后点击左上角运行即可
更多详情 https://reactnative.cn/docs/getting-started.html
3. 远程调试
ctrl + R ctrl + D
Enable Live Reload
当你的js代码发生变化后, React Native
会自动生成bundle然后传输到模拟器或手机上
在浏览器中打开 http://localhost:8081/debugger-ui
巧用Sources面板
指定模拟的设备类型
- 你可以使用
--simulator
参数,在其后加上要使用的设备名称来指定要模拟的设备类型(目前默认为"iPhone X"
)。如果你要模拟iPhone 4s
,那么这样运行命令即可:react-native run-ios --simulator "iPhone 4s"
。 - 你可以在终端中运行
xcrun simctl list devices
来查看具体可用的设备名称
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 SDK Android SDK Platform Performance (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
“。
在 SDK Manager
中选择” SDK Platforms
“选项卡,然后在右下角勾选” Show Package Details
“。展开 Android 8.1 (Oreo)
选项,确保勾选了下面这些组件(重申你必须使用稳定的翻墙工具,否则可能都看不到这个界面):
Android SDK Platform 27 Intel x86 Atom_64 System Image
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
版本。你可以同时安装多个其他版本
最后点击” 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自带工具运行
使用genymotion模拟器
去官网需要注册并下载 https://www.genymotion.com/,需要注册登录再下载的。注意下载`with virtualBox`版本,然后安装完成后需要登录,就是刚才注册的账号。登录后进入这个页面做两个操作
点击 settings
,选择 adb
设置 sdk
就是刚才一直用的 sdk
安装路径,如下
启动项目,点击 genymotion
里的 start
启动我们刚才安装好的的虚拟设备,是这个样子的,此时我们刚才初始化的项目还没连上虚拟设备
然后在我们的工程项目里执行 adb devices
会列出当前启动的虚拟设备,能检测到说明没问题,如下图里最后一行显示的就是刚才我们开启的 genymotion
那台虚拟设备
最后项目目录里执行
react-native run-android
打开 genymotion
,欢迎页面出来了,成功,修改一下文字,重新加载一遍,成功
- 第一次默认不是热加载形式,就是改变文件内容需要手动刷新的,这里设置一下热加载,以后内容这里就会自动刷新,
mac
是执行command+r
,选择第四个hot reloading
运行 react-native run-andriod
会下载很多东西,然后出现这个标志说明编译没有问题,还缺少一个模拟设备
如果是安卓5.0以下需要配置一下IP
1.2 安卓设备真机调试
1. 开启 USB 调试
在默认情况下 Android
设备只能从应用市场来安装应用。你需要开启 USB
调试才能自由安装开发版本的 APP
2. 通过 USB 数据线连接设备
下面检查你的设备是否能正确连接到 ADB(Android Debug Bridge)
,使用 adb devices
命令:
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://blog.csdn.net/yiifaa/article/details/78862507
二、矢量图标的运用
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 getPackages() { return Arrays.asList( new MainReactPackage() + , new VectorIconsPackage() ); }
到这里配置就全部完成,接下来就可以在 rn
项目中使用 iconfont
2.2 IOS平台
打开你的 Xcode
项目工程,右键工程文件,选择 react
项目下的 node_modules/react-native-vector-icons/Fonts
文件
在xcode的Info.plist文件中,加入: Fonts provided by application数组
打开终端,输入: rnpm link
,回车后会看到 Fonts provided by application
下加入如下字体
重新运行 react
项目,终端输入: react-native run-ios
,可以看到效果了
三、react-native-router-flux的使用
https://github.com/aksonov/react-native-router-flux
3.1 简介
特性
react-native-router-flux
是一个路由包.在一个中心区域定义可切换 scene
模块。在使用过程中,跟 react-native
提供的 navigator
的区别是你不需要有 navigator
对象。你可以在任意地方使用简单的语法去控制 scene
的切换,如: Actions.login({username, password})
or Actions.profile({profile})
or 甚至 Actions.profile(123)
,其中 login
profile
等是路由的 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 ( {/* 这种写法是将全部的跳转页面都放在Root下面 */} {/* key 就是给页面的标签,供Actions使用 */} {/* component 设置关联的页面 */} {/* title 就是给页面标题 */} {/* initial 就是设置默认页面*/} ); };
第二种使用方式
你可以在编译期定义你所有的 scenes
,并在后面的 Router
里面使用
import {Actions, Scene, Router} from 'react-native-router-flux'; const scenes = Actions.create( ); /* ... */ class App extends React.Component { render() { return } } {Actions, Scene, Router} from 'react-native-router-flux'; const scenes = Actions.create( ); /* ... */ class App extends React.Component { render() { return } }
在任意地方通过导入
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 ( {/* 这种写法是将全部的跳转页面都放在Root下面 */} {/* key 就是给页面的标签,供Actions使用 */} {/* component 设置关联的页面 */} {/* title 就是给页面标题 */} {/* initial 就是设置默认页面*/} ); };
// PageOne 的核心代码,点击 Text 跳转到下一个页面 //导入Action的包,处理页面跳转 import { Actions } from 'react-native-router-flux'; const PageOne = () => { return ( Actions.two()} > 我是Page One ); };
// PageTwo 的核心代码 export default class PageTwo extends Component { render() { return ( 我是Page Two ) } }
运行就可以看到下面的效果:
简单就完成了两个页面之间的切换
每一个 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 ( Actions.pop({ //refresh用于刷新数据 refresh: { data: '从 three 回到 two' } })}>我是Page Three ); };
PageTwo
也要修改一下代码
import {Actions} from 'react-native-router-flux'; // New code export default class PageTwo extends Component { render() { const data = this.props.data || "null"; return ( Actions.three({data: "从 two 传递到 three"})} >我是Page Two refresh:{data} ) } }
最后到 Root.js
添加新的 Scence
const Root = () => { return ( //........... ); };
此时运行就可以看到页面数据传递的效果了
可以看到从 PageThree
回到 PageTwo
数据传递并刷新页面的效果,不过如果需要实时刷新当前页面呢?这时就需要使用 Actions.refresh
方法了
export default class PageTwo extends Component { render() { const data = this.props.data || "null"; return ( Actions.three({data: "从 two 传递到 three"})} >我是Page Two Actions.refresh({ data: 'Changed data', })} > refresh:{data} ) } }
Tab Scene
通过设置 Scene
属性的 Tabs
可以设置 Tabs
。这个也开发中经常用到的页面效果
//设置tab选中时的字体颜色和标题 const TabIcon = ({focused , title}) => { return ( {title} ); }; const Root = () => { return ( {/*tabBarPosition设置tab是在top还是bottom */} ) };
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
此路由器的最重要的组件, 所有 组件必须要有一个唯一的
key
。父节点 不能将
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 (
or
)
标签栏组件
你可以使用 中的所有
props
来作为 的属性。 如果要使用该组件需要设置
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 (
)
将场景组合在一起的组件,用于自己的基于堆栈实现的导航。使用它将为此堆栈创建一个单独的 navigator
,因此,除非您添加 hideNavBar
,否则将会出现两个导航条
3.3.5 Tab Scene (child
within Tabs)
用于实现 Tabs
的效果展示,可以自定义 icon
和 label
Property | Type | Default | Description |
---|---|---|---|
icon |
component |
undefined |
作为选项卡图标放置的 RN 组件 |
tabBarLabel |
string |
tabbar 上的文字 |
3.3.6 Drawer (
or
)
用于实现抽屉的效果,如果要使用该组件需要设置 。
Property | Type | Default | Description |
---|---|---|---|
drawerImage |
Image |
替换抽屉 hamburger 图标,你必须把它与 drawer 一起设置 |
|
drawerIcon |
React.Component |
用于抽屉 hamburger 图标的任意组件,您必须将其与 drawer 道具一起设置 |
|
hideDrawerButton |
boolean |
false |
是否显示 drawerImage 或者 drawerIcon |
drawerPosition |
string |
抽屉是在右边还是左边。可选属性r ight 或 left |
|
drawerWidth |
number |
抽屉的宽度(以像素为单位)(可选) |
3.3.7 Modals (
or
)
想要实现模态,您必须将其 作为您
Router
的根场景。在 Modal
将正常呈现第一个场景(应该是你真正的根场景),它将渲染第一个元素作为正常场景,其他所有元素作为弹出窗口(当它们 被 push
)
示例:在下面的示例中, root
场景嵌套在 中,因为它是第一个嵌套
Scene
,所以它将正常呈现。如果要 push
到 statusModal
, errorModal
或者 loginModal
,他们将呈现为 Modal
,默认情况下会从屏幕底部向上弹出。重要的是要注意,目前 Modal
不允许透明的背景。
//... import components
3.3.8 Lightbox (
)
Lightbox
是用于将组件渲染在当前组件上 Scene
的组件 。与 Modal
不同,它将允许调整大小和背景的透明度
在下面的示例中, root
场景嵌套在中 ,因为它是第一个嵌套
Scene
,所以它将正常呈现。如果要 push
到 loginLightbox
,他们将呈现为 Lightbox
,默认情况下将放置在当前场景的顶部,允许透明的背景
//... import components {/* Lightbox components will lay over the screen, allowing transparency*/}
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上,我们可能想要用一个路由器来打开我们的
和参数
{ id: 1234 }
- 在移动设备上,如果我们正确地设置了
Android / iOS
环境来启动我们的应用程序并打开RNRF
,,那么我们还需要导航到我们的移动场景和参数
{ id: 1234 }
如果用户点击 http://thesocialnetwork.com/profile/1234/
在他们的设备,他们会打开 ,然后调用操作
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 ( just red just bigblue bigblue, then red red, then bigblue ); } } const styles = StyleSheet.create({ bigblue: { color: 'blue', fontWeight: 'bold', fontSize: 30, }, red: { color: 'red', }, }); AppRegistry.registerComponent('LotsOfStyles', () => LotsOfStyles);
常见的做法是按顺序声明和使用 style
属性,以借鉴 CSS
中的“层叠”做法(即后声明的属性会覆盖先声明的同名属性)
4.3 高度与宽度
最简单的给组件设定尺寸的方式就是在样式中指定固定的 widt
h和 height
。 React Native
中的尺寸都是无单位的,表示的是与设备像素密度无关的逻辑像素点
import React, { Component } from 'react'; import { AppRegistry, View } from 'react-native'; class FixedDimensionsBasics extends Component { render() { return ( ); } }; // 注册应用(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`试试看? ); } }; 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 ( this.setState({text})} /> {this.state.text.split(' ').map((word) => word && ':pizza:').join(' ')} ); } }
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( Scroll me plz ); } }
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 ( {item.key}} /> ); } } 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
尺寸
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
:row
column
row-reverse
column-reverse
-
flexWrap
:wrap
nowrap
-
justifyContent
:flex-start
flex-end
center
space-between
space-around
-
alignItems
:flex-start
flex-end
center
stretch
5.3.2 横轴和竖轴
主轴即水平方向的轴线,可以理解成横轴,侧轴垂直于主轴,可以理解为竖轴
5.3.3 flexDirection
-
flexDirection
:row
column
row-reverse
column-reverse
-
flexDirection
属性定义了父视图中的子元素沿横轴或侧轴方片的排列方式
row row-reverse column(default) column-reverse
1 2 3 4
5.3.4 flexWrap
flexWrap
属性定义了子元素在父视图内是否允许多行排列,默认为 nowrap
nowrap flex wrap flex
5.3.5 justifyContent
-
justifyContent
属性定义了浏览器如何分配顺着父容器主轴的弹性(flex
)元素之间及其周围的空间,默认为flex-start
-
justifyContent
:flex-start
flex-end
center
space-between
space-around
flex-start(default) flex-end center space-between space-around
5.3.6 alignItems
alignItems
属性以与 justify-content
相同的方式在侧轴方向上将当前行上的弹性元素对齐,默认为 stretch
。
flex-start flex-end center stretch
5.3.7 alignSelf
alignSelf
属性以属性定义了 flex
容器内被选中项目的对齐方式。注意: alignSelf
属性可重写灵活容器的 alignItems
属性
stretch center flex-start flex-end
1
5.3.8 flex
flex
属性定义了一个可伸缩元素的能力,默认为 0
flex:1 flex:2 flex:3
5.4 视图边框
borderBottomWidth number borderLeftWidth number borderRightWidth number borderTopWidth number borderWidth number borderColor borderColor
5.5 尺寸
width number height 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
的外部容器设置一个高度
;
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
提示:我们在使用具有不同分辨率的图标时,一定要引用标准分辨率的图片如 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() */
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: , headerRight: ( ), }; }; 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
启动页
- 在
react-native
的android
中的启动图和IOS
不相同点在于,android
没有默认的启动图,在IOS
里面有 - 使用插件
import SplashScreen from 'react-native-splash-screen';
- https://github.com/crazycodeboy/react-native-splash-screen
react-native ios端icon和启动图的设置
https://www.jianshu.com/p/b49629529a95
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
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 } }
3. 减少打包apk大小
4. 输出目录
android/app/build/outputs/apk/