背景
世界杯期间开始了从安卓开发转到了React-Native开发的学习,现在记录一下学习过程。基本上都是参考React-Native的中文文档,链接如下:
https://reactnative.cn/docs/0.31/getting-started.html#content
我的开发环境是mac,并且之前已经安装了homeBrew、Android Studio,并且已然把AS的sdk目录添加到了环境变量$PATH中
搭建环境
1、安装node
brew install node
2、设置npm镜像
npm config set registry https://registry.npm.taobao.org --global
npm config set disturl https://npm.taobao.org/dist --global
3、安装react-native-cli
npm install -g react-native-cli
4、安装watchman、flow
brew install watchman
brew install flow
5、新建目录,初始化项目
react-native init StudyOfRNListView
StudyOfRNListView是个项目名,随便取就行,这条命令执行完会在当前目录下,生成一个StudyOfRNListView文件夹,里面就是RN项目框架
这个过程可能很慢,不愿意等的可以直接从网上把别人的项目拷下来,把里面的逻辑代码都删掉
6、在StudyOfRNListView/android根目录下,新建local.properties文件,把sdk目录填进去,示例如下
sdk.dir=/Users/songzeceng/Library/Android/sdk
7、运行项目
这时要保证一个android手机或avd已经连接
cd StudyOfRNListView
react-native run-android
不出意外的话,应用就已经安装好了,点击就能运行
修改App.js
打开StudyOfRNListView目录,目录结构如下
主界面是index.js,内容如下
import { AppRegistry } from 'react-native';
import App from './App';
AppRegistry.registerComponent('StudyOfRNListView', () => App);
第一行从react-native里导入了AppRegistry,用{}扩起来是为了在后面可以作为一个对象使用
第二行从当前目录下的App导入了App(其实就是复制粘贴,但没有{}扩住,就不能调用里面的东西)
第三行是注册组件,组件名是App,然后把它作为StudyOfRNListView的入口类
而后我们就打开App.js,把里面的内容删到只剩下
import React, {Component} from 'react';
import {
AppRegistry,
Text
} from 'react-native';
class StudyOfRNListView extends Component {
render() { // render()方法用来渲染UI
}
}
这样,应用就只剩下一个白板,我们开始正儿八经学习rn,而主要的改动,就是在这个App.js里面,以StudyOfRNListView为中心进行的
每修改一些东西,晃一晃手机,就会显示菜单,选择reload就可以刷新界面(avd的话,直接在键盘上双击r就可以刷新)
如果reload报错,说连不上服务器,可以先登录这个网站看看出错原因:
http://localhost:8081/index.android.bundle?platform=android
如果显示是找不到index.android.js,解决方法可以参考这篇文章,也就是重启服务器并清空缓存,然后在另一个命令行下,启动项目
显示图片
首先要从react-native中导入Image
import React, {Component} from 'react';
import {
AppRegistry,
Text,
Image
} from 'react-native';
然后把StudyOfRNListView改成下面的样子
export default class App extends Component<Props> {
render() {
let pic = {
uri: "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=746951351,3068781139&fm=200&gp=0.jpg" // 注意是uri,不是url,这里赋值用:
}
return (
<View>
<Image source={pic} style={{width:200, height:200}}></Image> // source指定数据源,style用来指定样式
</View>
);
}
}
效果如下
自定义模块
rn支持我们自定义模块类,方才说的StudyOfRNListView相当于一个主模块类
定义一个城市名的模块类,可以是这样:
class City extends Component { // 模块类必须继承自Component
render() { // 至少要有一个render方法,这个方法用来渲染UI
return ( // return的就是我们想要渲染的东西
<Text>{this.props.name}</Text> // <Text>用来显示文字,开始标签和结束标签之间的内容表示显示的是props.name,这个我们可以在使用的时候指定
);
}
}
这里用到了属性props,这个东西一经设定就不能再改了,相应的可以改动的是状态state.
然后我们可以在主模块类StudyOfRNListView中使用
export default class App extends Component<Props> {
render() {
let pic = {
uri: "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=746951351,3068781139&fm=200&gp=0.jpg"
}
return (
<View>
<Image source={pic} style={{width: 200, height: 200}}></Image>
<City name={"安阳"}/>
<City name={"新乡"}/>
<City name={"洛阳"}/>
</View>
);
}
}
效果如下
state的使用-定时闪烁
属性一经设定不能再变,但状态可以。
新建一个组件Blink,添加构造方法和render方法如下
class Blink extends Component {
constructor(props) {
super(props); // 必须先调用父类构造方法
this.state = {showText: true}; // 设定初始化state
setInterval(() => { // 设置间隔的函数
this.setState({showText: !this.state.showText}); // 参数1:回调函数,内容:setState()用来设置state,把showText取反
}, 1000); // 参数2:间隔时间
}
render() {
let display = this.state.showText ? "黄埃散漫风萧索,云栈萦纡登剑阁" : ""; // 根据state里的showText决定显示内容
return (
<Text>{display}</Text> // 显示display
);
}
}
在主模块调用
export default class App extends Component<Props> {
render() {
let pic = {
uri: "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=746951351,3068781139&fm=200&gp=0.jpg"
}
return (
<View>
<Image source={pic} style={{width: 200, height: 200}}></Image> // rn里的尺寸都是无单位的逻辑像素点,和设备无关
<City name={"安阳"}/>
<City name={"新乡"}/>
<City name={"洛阳"}/>
<Blink/> // 调用Blink
</View>
);
}
}
效果
样式
我们可以向css那样自定义样式,调用的是StyleSheet.create()方法,所以要事先从'react-native'中导入StyleSheet
import {
AppRegistry,
StyleSheet,
Text,
View
} from 'react-native';
然后就可以自定义样式了,格式是json格式
const styles = StyleSheet.create({
bigBlue: {
color: "blue",
fontWeight: "bold",
fontSize: 30
},
red: {
color: "red",
}
});
样式在使用的时候,可以以数组的形式传入,在以数组的形式传入时,后面元素会覆盖前面的元素(当然只有相同类型的元素才会覆盖)
先在主模块里调用:
export default class App extends Component<Props> {
render() {
return (
<View>
<Text style={styles.bigBlue}>蓝色大号</Text>
<Text style={styles.red}>红色</Text>
<Text style={[styles.bigBlue, styles.red]}>蓝色大号,红色</Text> // 数组形式,先传入bigBlue,再传入red
<Text style={[styles.red, styles.bigBlue]}>红色,蓝色大号</Text> // 数组形式,先传入red,再传入bigBlue
</View>
);
}
}
效果
flexBox
flexBox用来指定子结点的展示形式,以根结点为例,用法如下
class StudyOfRNListView extends Component {
render() { // render()方法用来渲染UI
let pic = {
uri: 'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=746951351,3068781139&fm=200&gp=0.jpg'
};
return ( // return的内容就是渲染的内容
<View style={{
alignItems: 'center',
flex: 1,
// flex是权重
flexDirection: 'row',
// flexDirection是排列方向,排成一列column或者排成一排row
flexWrap: 'wrap',
// flexWrap:内容包裹形式。nowrap:不换行,此为默认 wrap:换行,wrap-reverse:换行,第一行在下面
justifyContent: 'space-around'
// justifyContent意为内容的分布方式,可选项有:flex-start、center、flex-end、space-around、space-between
// 以横向排列为例,意思依次是左对齐,居中,右对齐,每个子项两侧间隔相等(所以不会靠两侧),每个子项之间的间隔相等(所以会靠两侧)
}}>
<Image source={pic} style={{width: 200, height: 200}}/>
<City name='安阳' fontSize={50}/>
<City name='新乡' fontSize={30}/>
<City name='洛阳' fontSize={20}/>
<Text style={styles.red}>红色</Text>
<Text style={styles.bigBlue}>蓝色大号</Text>
<Text style={[styles.red, styles.bigBlue]}>红色、蓝色大号</Text>
<Text style={[styles.bigBlue, styles.red]}>蓝色大号、红色</Text>
</View>
);
}
}
效果如下
处理输入
正如Android里面的EditText一样,RN里面专门用来让用户输入的组件叫做TextInput,里面可以设置默认文字,事件处理等。
自定义一个组件,用来显示用户输入的内容
class CityInput extends Component {
constructor(props) {
super(props);
this.state = {text: ""}; // 默认text是空
}
render() {
return (
<View>
<TextInput
style={{height: 40}}
placeholder={"输入你要去的城市"} // 占位字符串
// onChangeText={ // 输入内容有变时调用
// (text) => this.setState({text})
// }
onSubmitEditing={ // 按下软键盘上的确认键后调用,参数是event
(event) => this.setState({text:event.nativeEvent.text})
// 通过调用event.nativeEvent.text获取输入的字符串
}
></TextInput>
<Text style={{padding: 10, fontSize: 30}}>
{
this.state.text.split('-').map( // split函数:分割,map函数:转换
(str) => "那就去" + str
).join('\n') // 字符串拼接
}
</Text>
</View>
);
}
}
主模块中调用
export default class App extends Component<Props> {
render() {
return (
<View style={{
alignItems: 'center',
flex: 1,
// flex是权重
flexDirection: 'row',
// flexDirection是排列方向,排成一列column或者排成一排row
flexWrap: 'wrap',
// flexWrap:内容包裹形式。nowrap:不换行,此为默认 wrap:换行,wrap-reverse:换行,第一行在下面
justifyContent: 'space-around'
// justifyContent意为内容的分布方式,可选项有:flex-start、center、flex-end、space-around、space-between
// 以横向排列为例,意思依次是左对齐,居中,右对齐,每个子项两侧间隔相等(所以不会靠两侧),每个子项之间的间隔相等(所以会靠两侧)
}}>
<CityInput/>
</View>
);
}
}
效果
结语
这是rn最基本的使用,应该多多练习以便掌握