1 前言
我们知道RN中任何界面元素都可以看成组件,小到一个按钮,大到一个页面。RN开发就是不停的开发组件和使用组件,并让他们协同工作,这样高效率协同的运行起来,这样就能完成一个APP的功能了
在实际的开发中,我们经常需要自定义一些满足我们项目开发的自定义组件,类似于Android开发中的自定义View。不过RN中自定义组件比Android中自定义View稍微简单一些。下面以一个计数器Counter的例子来记录一下RN中自定义的组件的开发流程。
2 RN中自定义组件步骤
一般来说RN中自定义组件有以下几步
1 继承RN的Component
这个不必说,只有是它的子类我们才能被RN渲染出对应的View视图
2 复写render()方法返回组件的视图呈现
这个方法主要是返回一个我们组件想呈现出的界面,例如时一个圆,长方形,还是不规则图形,或者说一些View的组合等。
3 定义组件属性以便于组件与父组件或子组件的交互接口
因为一般来说,我们的组件都是需要来使用的,有可能被当做子组件使用,这个时候需要父组件给它传递一些属性,或者它作为某些组件的父组件来使用。因此我们需要定义好一些属性作为组件对外交互的接口
4 处理组件的内部逻辑
这里主要涉及到组件的内部逻辑,比如点击事件,触摸事件,以及相应内部state状态的维护等
5 使用组件
主要需要注意的是,是否需要传递给组件的属性,以及使用组件的功能等。
3 自定义Counter组件
我们以最开头的一个计数器为例,它主要有以下功能
1 点击+,可以使计数器+1
2 点击-,可以让计数器-1
3 可以具体输入具体值
4 外部组件可以调用组件的getCount()获取最终的值
5 当计数器的值发生改变时可以回调给使用它的父组件
基于以上需求,我们可以定义如下的一个Counter组件
import React,{ Component } from 'react';
import {StyleSheet, Text, TextInput, TouchableOpacity, View} from "react-native";
import {PropTypes} from "prop-types";
/**
* 计数器
*/
export default class Counter extends Component{
/**
* 定义默认属性
* @type {{}}
*/
static defaultProps = {
initValue:0,
};
/**
* 属性类型
* @type {{}}
*/
static propTypes = {
initValue:PropTypes.number,
onValueChange:PropTypes.func,
};
/**
* 构造方法
* @param props
*/
constructor(props){
super(props);
//初始状态
this.state = {
value : this.props.initValue,
};
}
//组件渲染布局
render(){
return (
<View style={[styles.operatingBox,this.props.styles]}>
<TouchableOpacity activeOpacity={0.2}
style={styles.reduce}
onPress={this.reduce.bind(this)}>
<Text allowFontScaling={false} style={styles.btn1}>-</Text>
</TouchableOpacity>
<View style={styles.inputBox}>
<TextInput style={styles.input1}
value={this.state.value.toString()}
maxLength={9}
keyboardType='numeric'
autoFocus={false}
underlineColorAndroid='transparent'
onEndEditing={this.checkInput.bind(this)}
onChangeText={this.onChangeText.bind(this)}>
</TextInput>
</View>
<TouchableOpacity activeOpacity={0.2}
style={styles.plus}
onPress={this.plus.bind(this)}>
<Text allowFontScaling={false} style={styles.btn1}>+</Text>
</TouchableOpacity>
</View>
);
}
//减少计数
reduce(){
this.updateValue(this.state.value-1);
}
//增加计数
plus(){
this.updateValue(this.state.value+1);
}
updateValue(newValue){
this.setState({
value: newValue,
});
this.props.onValueChange(newValue);
}
//检查输入的内容
checkInput(){
let res = this.state.value;
if (res === '' || res < 0) {
res = 0;
} else {
res = Math.floor(res); //舍去小数
}
this.updateValue(res);
}
//内容改变函数
onChangeText(txt){
this.setState({
value:Number(txt)
});
this.props.onValueChange(Number(txt));
}
//返回数值
getCount(){
return this.state.value;
}
}
//样式
const styles = StyleSheet.create({
operatingBox: {
margin:5,
width: 120,
height:35,
borderColor:'gray', //边框颜色
borderWidth:1,
borderRadius: 5, //圆角半径
flexDirection:'row', //主轴布局
alignItems: 'center', //侧轴对齐方式
overflow: 'hidden', //超过控件范围的隐藏
},
btn1:{
fontSize:18,
textAlign:'center',
backgroundColor:'transparent', //透明颜色
},
inputBox:{
flex:1, //
borderRightWidth:1, //右边距
borderRightColor:'gray', //颜色
},
reduce:{
width:34,
height:34,
justifyContent:'center',
borderRightWidth:1, //右边距
borderRightColor:'gray', //颜色
},
plus:{
width:34,
height:34,
justifyContent:'center',
},
input1:{
flex:1,
backgroundColor:'transparent', //透明
textAlign:'center',
padding:0,
fontSize:14,
},
});
可以看到,我们最外层View定义了一个圆角矩形框,然后分别使用了两个按钮,一个输入框来完成我们的功能。
并且定义了如下属性
initValue:PropTypes.number, //初始值
onValueChange:PropTypes.func, //回调函数
在内部定义了状态value,用于显示具体的值
并且定义了一个方法用于获取value
//返回数值
getCount(){
return this.state.value;
}
4 使用Counter组件
使用该组件很简单,我们直接在父组件中引用它即可,如下:
import React,{Component} from "react";
import {View, StyleSheet, Text, TouchableOpacity} from "react-native";
import Counter from "../component/Counter";
export default class CountDemo extends Component{
constructor(props) {
super(props);
this.state = {
value: 0,
};
}
render() {
return (
<View style={styles.container}>
<Counter
ref={(count) => this.count = count}
initValue={10}
onValueChange={(value) => this._onValueChange(value)}
/>
<View>
<Text>{this.state.value}</Text>
</View>
<TouchableOpacity onPress={() => this.getValue()}>
<Text>点击获取值</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => this.clearValue()}>
<Text>清理</Text>
</TouchableOpacity>
</View>
);
}
_onValueChange(value) {
this.setState({
value:value,
});
}
getValue(){
this.setState({
value:this.count.getCount(),
});
}
clearValue(){
this.setState({
value:0,
});
}
}
//样式
const styles = StyleSheet.create({
container: {
flex:1,
borderColor:'#DDD', //边框颜色
alignItems: "center"
},
count:{
backgroundColor:"#FF22FF",//
width:50,
height: 30,
}
});
运行效果如下:
参考:
另外源码请参考如下:
https://github.com/qiyei2015/ReactNative/tree/master/project/GitHub