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应用

搭建好开发环境后,我们就可以使用RN开发原生APP了。在cmd中键入下列命令就可以生成一个RN的helloworld项目,并在android机器上运行起来

react-native init AwesomeProject
cd AwesomeProject
react-native run-android

运行起来后就是下面的界面

image

可以看到界面中也给了我们相应的提示,打开工程根目录中的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,就更新界面了。

image

我们还可以使用Ctrl+M呼出开发者菜单,真机的话,摇一摇即可。
image

上图的菜单先简单介绍几个,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表达式。接触过angularvue的同学应该对这种写法会比较熟悉。再说明一点,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也只能指定一个数字值。在平常开发的时候,使用flexDirectionalignItemsjustifyContent三个样式属性就已经能满足大多数布局需求,使用flexDirection决定布局的主轴,justifyContent决定子元素在主轴上的位置,alignItems决定子元素在次轴上的位置。举个栗子吧,这样比较形象一点,比如下图所示的界面

image

图中卡片布局的大致实现代码如下

            <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控件,TouchableHighlightTouchableNativeFeedbackTouchableOpacityTouchableWithoutFeedback

<TouchableHighlight onPress={this._onPressButton} onLongPress={this._onLongPressButton}>
        <Text>Button</Text>
</TouchableHighlight>

上下左右滑动可以使用ScrollView组件,复杂的手势请参考PanResponderAPI

异步问题

因为RN中只有一个JS执行线程,是不能直接开启一个异步线程的来执行耗时操作的,但是可以使用InteractionManager来保障UI的渲染性能的。

InteractionManager.runAfterInteractions(() => {
   // ...需要长时间同步执行的任务...
});

资源引用

使用require方法来引用项目中的静态资源,如.png,.mp3,.wav,mp4,.mov,.html.pdf
比如Image控件的使用

<Image source={require('./my-icon.png')} />
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,800评论 25 707
  • 简短说明 收录一些好用的RN第三方组件,以方便日常的使用,大家有什么推荐的也可以跟我说,我加进去。如有冒犯,可以联...
    以德扶人阅读 43,620评论 44 214
  • 最近在学习ReactNative开发,感觉还是很容易上手的,搜集了不少资料,分享给大家。 为什么选ReactNat...
    StChris阅读 1,638评论 0 37
  • 昨晚做了个梦,我一个人走在路上,四周天气昏暗,浓雾重重。我也不知道自己要去哪,就径直朝前面走着,走着,突然前面出现...
    子悠说财阅读 316评论 0 2
  • 蜗牛身上背着重重的壳。相较于它们平均10厘米的身体长度而言。这只壳几乎掩盖了它们身体百分之八十的面积。除...
    歌龄阅读 371评论 6 4