React-Native 中自定义checkbox组件

文章目录
  1. checkbox组件封装
    1. 准备条件
    2. 组件核心代码
    3. ListView 初始化
    4. renderRow 行数据渲染
    5. checkbox全选及单选的原理
    6. checkbox的取值

感觉有一段时间没写东西了,原因是从年初来了后,公司开展了移动端的业务,用的是React-native 这个前端框架,所以这段时间一直很忙,需要去研究 React的Api、语法、兼容性、难点突破等等。

这次给大家分享一下 React中 ListView这个组件以及全选和单选按钮的封装使用。当然核心部分还是讲解自定义封装的 checkbox 组件!
React 有一个优势就是组件的复用性特别高,在原生组件中,官方并没有向我们提供checkbox这样的多选或单选的组件,因此需要我们自己去封装。

checkbox组件封装

准备条件

若我们需要在列表的右侧展现checkbox那样的复选框,一般在网页中会有自带的checkbox标签元素,那在react中我们需要用图片或者字体图标来实现checkbox样式的显示,当然也可以通过样式来控制

  • 字体图标方式
    在此我们需要通过npm的方式去安装 字体图标的依赖包,传送门 点我点我

    1
    2
    3
    4
    5
    6
    7
    8
    npm install react-native-vector-icons --save

    安装完毕后,我们通过require的方式,将包导入进来,如下
    var Icon=require('react-native-vector-icons/FontAwesome');

    render(){
    return <Icon name='square-o' size={16} style={styles.checkbox} color="#00B4F7" ></Icon>
    }
  • 图片方式
    这种就比较简单了,直接用原生的Image组件去加载本地的资源图片就可以了,设计好checkbox 选中和未选中两张图片,通过state去切换图片的source属性。

    1
    2
    3
    4
    5
    var sourceUrl = require('image!selected');
    if(this.state.checked){
    sourceUrl = require('image!unselected');
    }
    <Image source={sourceUrl}></Image>

组件核心代码

这里组件的编码,我暂时用的es6的语法,不清楚es6与es5 ,请前往此处去了解 传送门

//这里我就只贴出核心代码,关于checkbox的label属性及样式我就省略了,具体代码大家可以去github上fork或者下载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
var Icon=require('react-native-vector-icons/FontAwesome'); 
export default class CheckBox extends React.Component{
static defaultProps = {
checked: false
};
static propTypes={
checked: React.PropTypes.bool,
onChange: React.PropTypes.func
};
constructor(props){
super(props);
this.state = {
checked: props.checked,
};
}
componentWillReceiveProps(nextProps) {
this.setState({
checked: nextProps.checked
});
}
onChange() {
this.setState({checked:!this.state.checked});
}
toggle(){
console.log("checkbox被点击了");
this.setState({checked:!this.state.checked});
this.props.onChange(this.state.checked);
}
render() {
var source = "square-o";
if(this.state.checked){
source = "check-square-o";
}
var container = (
<View style={styles.container}>
<Icon name={source} size={16} style={styles.checkbox} color="#00B4F7" ></Icon>
</View>
);
return (
<TouchableHighlight ref="checkbox" onPress={this.toggle.bind(this)} underlayColor='white'>
{container}
</TouchableHighlight>
)
}
}

代码说明 :其实上面这段代码读起来应该没什么难度,定义了一个checked属性和一个回调的onChange事件,当点击TouchableHighlight时,调用toggle事件去改变当前checkbox的checked状态!

###checkbox在ListView中的应用
介绍了如何封装一个checkbox组件,因此我们可以在其他的组件中灵活的去调用自己封装的组件,接下来我们看看checkbox如何在列表中展现,如何拿到checkbox选中的值?
在此之前,我们需要在组件顶部导入checkbox这个组件!

1
import CheckBox from './common/checkbox';

ListView 初始化

我们在render方法中 初始化listview

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<View style={styles.container}>
<View style={{flex:1}}>
<ListView
dataSource={this.state.dataSource}
refreshControl={this.renderRefresher()}
renderRow={this.renderList.bind(this)}
initialListSize={20}
renderSeparator={this._renderSeparatorView}
style={styles.listView}/>
</View>
<View>
<TouchableHighlight underlayColor='#c8c7cc' onPress={()=>this.SelectAll()}>
<View style={[styles.btn,{backgroundColor:"#00CEF9",color:"#000"}]}><Text>全选</Text></View>
</TouchableHighlight>
</View>
</View>

  • this.state.dataSource 是我们listview的数据源
  • this.renderRefresher() 是本地写的一个方法 用来指定listview下拉刷新需要调用的控件,详细请看RefreshControl这个原生组件
  • this.renderList 渲染每行所调用的方法,也是我们需要着重去理解的,一般数据的绘制基本就是靠这个方法了

renderRow 行数据渲染

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
initCheckBoxData(checkbox){

if(checkbox!=null){
CheckBoxData.push(checkbox);
}
}
renderList(rowData,rowID) {
return (
<View style={styles.listRow} >
<View>
<CheckBox
ref={(c)=>this.initCheckBoxData(c)}
label=""
checked={false}
value={rowID}
style={styles.check}
onChange={(checked) => this.checkSelect(checked,rowID)} />
</View>
<View style={styles.rightContainer}>
<Text style={styles.title}>{rowData.title}</Text>
<Text style={styles.normal}>{rowData.desc}</Text>
<Text style={styles.normal}>时间:{rowData.pubDate}</Text>
<Text style={styles.normal}>来源:{rowData.source}</Text>
</View>
</View>
);
}

这个方法用来渲染每行数据,并提供了行对象和行索引,这里我做的是一个新闻列表。展示了新闻标题,描述,时间,来源等字段的展现,最左侧就是一个复选框,我们看到了 <CheckBox /> 这样的自定义组件出现在行数据中,为它指定了 onChange事件、value值绑定、checked默认值及ref输出当前对象,所以 initCheckBoxData 这个方法的作用就是将当前对象保存在一个共有的数组里面,全选的时候可以拿到每行的 Checkbox对象,并调用它自身的方法和属性。
干说了大半天,我们还是来看看效果图,界面比较丑,没有美化,望体谅哦…

结合listview展现checkbox

checkbox全选及单选的原理

  • 单选
    checkbox 本身外层包裹了一层 TouchableHighlight,TouchableHighlight设置了onPress事件,因此会去改变state里checked的状态,从而重新渲染当前checkbox,同时toggle事件里,调用了回调的onChange函数,将改变的值回传给前端的 checkSelect方法 onChange={(checked) => this.checkSelect(checked,rowID)}

    1
    2
    3
    4
    5
    checkSelect(checked,id){

    console.log(checked+",,,,"+id);

    }
  • 多选
    多选这里调用了SelectAll 这个方法,说这个方法之前,我先说说 Ref 属性的作用,这个属性的官方解释是:允许你引用 render() 返回的相应的支撑实例( backing instance ),这样就可以确保在任何时间总是拿到正确的实例。通俗点说抛出一个引用接口,供外面的对象去访问这个实例。

因此上面listview里渲染时,我们申明了一个 全局变量 var CheckBoxData={],通过ref 将当前对象全部push到CheckBoxData变量中。这样为后面全选时做准备,下面看看具体全选的方法:

1
2
3
4
5
6
7
8
SelectAll(){
for (var i = 0; i < CheckBoxData.length; i++) {
if(CheckBoxData[i]!=null){
console.log(CheckBoxData[i]);
CheckBoxData[i].onChange();
}
}
}

循环去变量CheckBoxData数组,并调用它自身的方法 onChange 去改变state里checked的状态,达到重新渲染的目的。我们在控制台输出看看 checkbox这个对象:

一句话:全选的实现无非就是拿到所有的checkbox对象,然后调用它自身的onChange事件 去改变state状态

checkbox的取值

取值就非常简单了,我们初始化的时候,为checkbox每个对象绑定了value值。
循环CheckBoxData这个数组时,我们可以拿到每个checkbox state里的checked状态,也能拿到props里的value值,从而知道哪些checkbox被选中了,值是多少!

checkbox组件 github地址 :传送门

华丽的分割线


自定义封装组件就介绍到这里,我也不清楚是否讲清楚了,如有不懂的可加群或者加我微信或者留言!!