2018-06-22 02:05
React Native 简单入门 (二)
React Native介绍
React Native 是Facebook开源的一个跨平台移动应用开发框架。直白点说,借助React Native你可以直接使用JS来开发原生移动应用。
React和React Native
React也是Facebook开源的一个框架,一个JS UI 框架,React Native 是以React为一部分基础的衍生产品。也就是说,除了JavaScript,你还需要熟悉一下React这个UI框架,以便于更好的上手React Native。
安装
使用React Native开发原生APP时,除了JS的Node环境,还是需要配置好相关的原生开发环境。Android的JDK和Android Studio,IOS的XCODE,当然一般还会装一些辅助的工具,这里就不详细说明了,React Native中文网上有详细的开发环境搭建说明文档。
- RN中文网 http://reactnative.cn/
- RN官网 https://facebook.github.io/react-native/
- 我自己的简书博客 http://www.jianshu.com/p/138807f257e7
第一个RN应用
搭建好开发环境后,我们就可以使用RN开发原生APP了。在cmd中键入下列命令就可以生成一个RN的helloworld项目,并在android机器上运行起来
react-native init AwesomeProject cd AwesomeProject react-native run-android
运行起来后就是下面的界面
可以看到界面中也给了我们相应的提示,打开工程根目录中的App.js
文件
/** * Sample React Native App * https://github.com/facebook/react-native * @flow */import React, { Component } from 'react';import { Platform, StyleSheet, Text, View } from 'react-native';const instructions = Platform.select({ ios: 'Press Cmd+R to reload,\n' + 'Cmd+D or shake for dev menu', android: 'Double tap R on your keyboard to reload,\n' + 'Shake or press menu button for dev menu', });export default class App extends Component<{}> { render() { return ( <View style={styles.container}> <Text style={styles.welcome}> Welcome to React Native! </Text> <Text style={styles.instructions}> To get started, edit App.js </Text> <Text style={styles.instructions}> {instructions} </Text> </View> ); } }const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF', }, welcome: { fontSize: 20, textAlign: 'center', margin: 10, }, instructions: { textAlign: 'center', color: '#333333', marginBottom: 5, }, });
修改render()方法中的返回
render() { return ( <View style={styles.container}> <Text style={styles.welcome}> Hello React Native! </Text> </View> ); }
然后选中模拟器双击键盘R
,就更新界面了。
我们还可以使用Ctrl+M
呼出开发者菜单,真机的话,摇一摇即可。
上图的菜单先简单介绍几个,Reload
就是加载资源即为刷新,Enable Hot Reload
为热加载,开启此选项,开发时代码变动,界面自动刷新。以后除非原生代码改动,可以使用npm start
快速开启调试服务,不需要每次都运行react-native run-android
然后再回过头看下App.js
的代码,可以发现React Native基本跟React是差不多的,只不过基础组件不是web组件而是原生组件。这里先列出RN的基础组件
- AccessibilityInfo
- ActivityIndicator
- Button
- CheckBox
- DatePickerIOS
- DrawerLayoutAndroid
- FlatList
- Image
- KeyboardAvoidingView
- ListView
- ListView.DataSource
- Modal
- NavigatorIOS
- Picker
- PickerIOS
- ProgressBarAndroid
- ProgressViewIOS
- RefreshControl
- ScrollView
- SectionList
- SegmentedControlIOS
- Slider
- StatusBar
- Switch
- TabBarIOS
- TabBarIOS.Item
- Text
- TextInput
- ToolbarAndroid
- TouchableHighlight
- TouchableNativeFeedback
- TouchableOpacity
- TouchableWithoutFeedback
- View
- ViewPagerAndroid
- VirtualizedList
- WebView
使用基础组件时先从react-native
包中导入,比如我们使用Button
时,先添加导入
import { Button } from 'react-native';
然后在reder方法中返回
render() { return ( <View style={styles.container}> <Button title={'hello rn'} onPress={()=>{ alert('hello rn') }}/> </View> ); }
各组件的使用可以阅读官方或中文网文档,有详细介绍。这里补充一些React的相关知识。前面的代码就有两个React的基础概念,Component组件和JSX语法,Component组件是React中很重要的一个概念,React组件使用render方法接收数据并输出JSX展示。上面代码中类似xml的写法就称为JSX,是react对js的一种语法扩展。JSX与xml语法类似,可以定义属性和子元素,不同的是通过{}
来加入js表达式。接触过angular
或vue
的同学应该对这种写法会比较熟悉。再说明一点,JSX也是一种表达式,在编译以后也会转换成普通的js对象。也就说你可以像下面这么用
let text = <Text>hello rn</Text>if(isAndroid) { return <Text>hello android</Text>}else{ return <Text>hello ios</Text>}let txts = []; txts.push(<Text>hello rn</Text>);
关于Component组件还有两个重要概念,props
(属性)和state
(状态),在组件内我们通过props
来访问传入的数据,比如说我们之前使用的button
组件
<Button title={'hello rn'}/>
在Button
类中,就可以通过props
访问到
class MyButton extends Component{ render () { let title =this.props.title ... } }
而state
是用来保持组件内部状态的,当state
改变时,组件会重新调用render()
方法,刷新组件UI。
class MyButton extends Component{ constructor(props){ super(props); this.state={ title:props.title } } onClick(){ this.setState({title:'isClicked'}) } }
在constructor()
构造方法中赋值,使用this.setState()
方法更新state
。
布局和样式
所有的基础组件都接收一个style
属性,接收一个对象或数组,组件的宽高背景等等都是通过这个属性来定制的
<View style={{ height:100, width:100, backgroundColor:'red' }}> ...</View>
使用的样式名基本都遵循了web上的css命名,只是按照JS的语法规范使用了驼峰命名法,列如background-color
改为backgroundColor
,而且给宽高设置的尺寸都是没有单位的,表示与设备像素无关的逻辑像素点。补充说明一下单位转换和尺寸适配的问题,单位方面,一般现在UI会给我们PxCook的源文件,Android的话,对照相应密度的dp大小设置即可。IOS,对照相应倍图的pt大小设置即可。屏幕尺寸方面,因为布局采用的是flexBox,所以对不同的屏幕尺寸基本上能提供一致的布局结构。其他更细节的适配需求,现在并没有系统整理,以后再和大家分享交流。
然后再说下FlexBox布局,RN中的FlexBox布局和Web上的CSS基本一致,但有两点差异,flexDirection
的默认值是column而不是row,而flex也只能指定一个数字值。在平常开发的时候,使用flexDirection
、alignItems
和 justifyContent
三个样式属性就已经能满足大多数布局需求,使用flexDirection
决定布局的主轴,justifyContent
决定子元素在主轴上的位置,alignItems
决定子元素在次轴上的位置。举个栗子吧,这样比较形象一点,比如下图所示的界面
图中卡片布局的大致实现代码如下
<View style={{alignItems:'center',justifyContent:'center',minHeight:100...}}> <Text style={{color:'white'...}}> 昨日票房 2017年11月7日 </Text> <View style={{flexDirection:'row',alignItems:'center',marginTop:20...}> <Text style={{color:'white',fontSize:24...}}> 701786 </Text> <Text style={{color:'white',marginTop:10}}> 万 </Text> </View> <Text style={{color:'white',,marginTop:20...}}> 每日0点更新票房 </Text> </View>
上面的代码只是大概布局思路,当然这个卡片的真正实现还用到了LinearGradient
控件和ImageBackground
控件。
页面跳转
我们一般使用React Navigation
来构建多页面以及跳转页面,使用前要先安装
yarn add react-navigation
然后在app.js
(如果你没改动index.js
中的app组件注册的话)注册页面
import { StackNavigator } from 'react-navigation';import Main from "./pages/main";import NationwideDetail from "./pages/cinema/nationwideDetail";import Cinema from "./pages/cinema/cinemaIndex";import DatePickerPage from "./pages/common/datePickerPage";import ForecastDetail from "./pages/cinema/forecastDetail";import CinemaDetail from "./pages/cinema/cinemaDetail";const RootNavigator = StackNavigator({ NationwideDetail:{ screen:NationwideDetail, }, Cinema:{ screen:Cinema }, DatePickerPage:{ screen:DatePickerPage }, ForecastDetail:{ screen:ForecastDetail }, CinemaDetail:{ screen:CinemaDetail } });export default RootNavigator;
最初显示第一个注册页面,注册完成之后,每个页面中的props
属性可以获得navigation
对象,通过navigation
对象进行页面跳转
this.props.navigation.navigate('NationwideDetail')
也可以携带参数
this.props.navigation.navigate('NationwideDetail',{name:'wuHuaRong'})
参数在navigation.state.params.name
中获取。
返回页面
我们还可以通过navigation.goBack()
方法关闭当前页面返回上个页面,navigation.goBack('NationwideDetail')
可以指定回到某个页面。如果还想关闭页面时返回某个值,类似android中的startActivityForResult
,需要再集成redux
状态机来管理多个页面之间的共享状态。此部分,先不详细说明了。
网络请求
RN提供了与web一致的Fetch API,也允许使用XMLHttpRequest API,以及基于XMLHttpRequest的第三方库frisbee或是axios,此部分文档有详细说明就不再赘诉了。
触摸
简单的点击和长按事件可以使用官方提供的四个Touchable
控件,TouchableHighlight
、TouchableNativeFeedback
、TouchableOpacity
、TouchableWithoutFeedback
<TouchableHighlight onPress={this._onPressButton} onLongPress={this._onLongPressButton}> <Text>Button</Text></TouchableHighlight>
上下左右滑动可以使用ScrollView
组件,复杂的手势请参考PanResponder
API
异步问题
因为RN中只有一个JS执行线程,是不能直接开启一个异步线程的来执行耗时操作的,但是可以使用InteractionManager
来保障UI的渲染性能的。
InteractionManager.runAfterInteractions(() => { // ...需要长时间同步执行的任务...});
资源引用
使用require
方法来引用项目中的静态资源,如.png
,.mp3
,.wav
,mp4
,.mov
,.html
和.pdf
等
比如Image
控件的使用
<Image source={require('./my-icon.png')} />