前言
之前的章节都停留在理论阶段,本节通过介绍一些常用组件的使用来进行实战。
基础组件
TextInput
这是一个文本输入框,类比Android的EditText
。之所以选择介绍它,是因为它的使用涉及了文本变换,数据回调等问题。理解了它就理解了大部分的组件的使用。
import React, {useState} from 'react';
import {Text, TextInput, View} from 'react-native';
const PizzaTranslator = () => {
const [text, setText] = useState(''); //(1)
return (
<View style={{padding: 10}}> //(2)
<TextInput
style={{height: 40}}
placeholder="Type here to translate!"//(3)
onChangeText={newText => setText(newText)} //(4)
value={text} //(5)
/>
<Text style={{padding: 10, fontSize: 42}}>
{text
.split(' ')
.map(word => word && '🍕')
.join(' ')}
</Text>
</View>
);
};
export default PizzaTranslator;
以上示例:实现了一个输入框,当用户输入时,会将输入的单词替换成🍕. (单词已空格分隔)
接下来我们逐步的分析代码
- (1)首先定义了页面中那些元素是可变的,使用useState定义text, setText
- (2)这里为View定义了内间距style样式,样式将再下一节详细讲解
- (3)placeholder代表TextInput未输入时的提示文案
- (4)onChangeText需要传递一个function当组件内容发生改变时会调用此方法,这里我们的回调函数需要使用setText重新设置text的值。
- (5)value属性传递的是text,这样当使用setText更改其内容时,输入框的值也会跟着改变
注:使用useState定义text这个状态非常重要。在原生Android中我们要实现类似的功能,我们可能要findById找到控件,然后通过get/set方法对属性进行设置。UI的变化实际是通过函数驱动,而使用useState则是修改数据源,数据改变驱动UI自动渲染。React native使用的是声明式编程,而原生Android采用函数式编程,在Android开发中常见的MVVM架构,也正是想向这种声明式编程靠拢。
TouchableHighlight
这是一个处理触摸事件的组件,类似的还有Button
、TouchableOpacity
、TouchableNativeFeedback
、TouchableWithoutFeedback
他们的区别是:
- TouchableHighlight:带有高亮效果的点击控件
- TouchableOpacity:带有透明变化效果的点击控件
- TouchableNativeFeedback:只用于Android系统带有水墨波纹效果的点击控件
- TouchableWithoutFeedback:没有任何特效的点击控件
- Button:RN自带的单个按钮组件
除了Button其余几个组件都可以包含子组件,实现更高的自定义
<TouchableHighlight
onPress={this._onPressButton}
onLongPress={this._onLongPressButton}
underlayColor="white">
<View style={styles.button}>
<Text style={styles.buttonText}>Touchable with Long Press</Text>
</View>
</TouchableHighlight>
- onPress\onLongPress传递函数,当用户触摸组件时就会触发回调
FlatList 和 SectionList
FlatList
用于展示一个滚动列表,与ScrollView不同的是,FlatList具有更高的性能,它仅渲染当前页面显示的内容。
import React from 'react';
import {FlatList, StyleSheet, Text, View} from 'react-native';
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 22,
},
item: {
padding: 10,
fontSize: 18,
height: 44,
},
});
const sourceData = [
{key: 'Devin'},
{key: 'Dan'},
{key: 'Dominic'},
{key: 'Jackson'},
{key: 'James'},
{key: 'Joel'},
{key: 'John'},
{key: 'Jillian'},
{key: 'Jimmy'},
{key: 'Julie'},
]
const FlatListBasics = () => {
return (
<View style={styles.container}>
<FlatList
data={sourceData}
renderItem={({item}) => <Text style={styles.item}>{item.key}</Text>}
/>
</View>
);
};
export default FlatListBasics;
- data:用于设置数据源
- renderItem:返回一个组件,用于表示每一个Item应该如何显示
sectionList
用于显示一个分组带标题的滚动列表。
import React from 'react';
import {SectionList, StyleSheet, Text, View} from 'react-native';
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 22,
},
sectionHeader: {
paddingTop: 2,
paddingLeft: 10,
paddingRight: 10,
paddingBottom: 2,
fontSize: 14,
fontWeight: 'bold',
backgroundColor: 'rgba(247,247,247,1.0)',
},
item: {
padding: 10,
fontSize: 18,
height: 44,
},
});
const SectionListBasics = () => {
return (
<View style={styles.container}>
<SectionList
sections={[
{title: 'D', data: ['Devin', 'Dan', 'Dominic']},
{
title: 'J',
data: [
'Jackson',
'James',
'Jillian',
'Jimmy',
'Joel',
'John',
'Julie',
],
},
]}
renderItem={({item}) => <Text style={styles.item}>{item}</Text>}
renderSectionHeader={({section}) => (
<Text style={styles.sectionHeader}>{section.title}</Text>
)}
keyExtractor={item => `basicListEntry-${item}`}
/>
</View>
);
};
export default SectionListBasics;
- sections:用于设置数据源,其中数据源的格式必须为[{title:“”, data:[]},…]。title代表每个分组的标题,data代表该分组下的每个子项
- renderItem:代表每个Item如何渲染
- renderSectionHeader:分组头部如何渲染
Image
用于展示一张图片,图片的来源可以是网络或者本地资源
//网络
<Image source={{uri: 'https://reactjs.org/logo-og.png'}}
style={{width: 400, height: 400}} />
//本地资源
<Image source={require('./my-icon.png')} />
对于本地图片,可能存在多个像素的情况,那么可以通过文件名后缀的形式,check.png、check@2x.png、check@3x.png
这样在通过require引用图片的时候,即可自动选择。
- 请求静态图片使用的require函数,它不仅可以获取到图片,还可以获取到
.mp3, .wav, .mp4, .mov, .html , .pdf
文件 - Image可以引用原生APP的资源,例如Android的drawable文件夹下的图片,
source={{uri: 'app_icon'}}
只需要使用uri接文件名即可实现,无需文件后缀名。如果想引入Android assets 文件夹下的文件,则使用source={{uri: 'asset:/app_icon.png'}}
- 对于网络图片,可以在Image中设置请求头,请求体等参数
<Image
source={{
uri: 'https://reactjs.org/logo-og.png',
method: 'POST',
headers: {
Pragma: 'no-cache',
},
body: 'Your Body goes here',
}}
style={{width: 400, height: 400}}
/>
- Image 支持base64形式图片:
source={{uri: 'data:image/png;base64,XXX==',}}
常用样式
大部分RN组件都有style属性,里面包含了非常丰富的属性,包括内外边距,布局位置,颜色等。可以直接在style里面设置也可以使用StyleSheet.create抽离出来,通常我们会将其抽离出来,提高代码可读性
import React from 'react';
import {StyleSheet, Text, View} from 'react-native';
const LotsOfStyles = () => {
return (
<View style={styles.container}>
<Text style={styles.red}>just red</Text>
<Text style={styles.bigBlue}>just bigBlue</Text>
<Text style={[styles.bigBlue, styles.red]}>bigBlue, then red</Text>//(1)
<Text style={[styles.red, styles.bigBlue]}>red, then bigBlue</Text>//(2)
</View>
);
};
const styles = StyleSheet.create({
container: {
marginTop: 50,
},
bigBlue: {
color: 'blue',
fontWeight: 'bold',
fontSize: 30,
},
red: {
color: 'red',
},
});
export default LotsOfStyles;
- 在(1)(2)处出现了style={[styles.bigBlue, styles.red]}的语法,这个是合理的,style确实支持传递数组,当传递数组时,数组后面的属性会覆盖数组前面的属性。
宽高
<View
style={{
width: 100,//or "30%"
height: 100,//or "30%"
backgroundColor: 'skyblue',
}}
/>
通过width、height设置组件宽高,形式可以是详细的数值,也可以是百分比。第二种方式是通过flex属性,flex是一种自适应的属性,例如
<View style={{flex: 1}}>
<View style={{flex: 1, backgroundColor: 'powderblue'}} />//(1)
<View style={{flex: 2, backgroundColor: 'skyblue'}} />//(2)
<View style={{flex: 3, backgroundColor: 'steelblue'}} />//(3)
</View>
其中(1)的占比为1/6,(2)的占比为2/6,(3)的占比为3/6
布局位置
如何定义组件在布局中的位置,以下链接中有详细的示例和解释
https://reactnative.dev/docs/flexbox
颜色
RN中通过字符串对颜色进行定义,共有三种定义方式:
"#FFFFFF"
"rgb(255, 0, 255)"
- 使用颜色名,例如
transparent、black
等