React Native之(支持iOS与Android)自定义单选按钮(RadioGroup,RadioButton)
一,需求与简单介绍
在开发项目时发现RN没有给提供RadioButton和RadioGroup这两个组件,只有CheckBox组件(不支持iOS),但是项目中确实有有一些地方需要使用到RadioButton和RadioGroup,比如默认地址的选择等。
需求:
- 可以指定选中状态和未选中状态的颜色。
- 可以指定该单选按钮是否可选:disabled。
- 可以指定整体的样式,就像使用系统组件一样,这个用style来接收。
- 可以自定义宽(width)高(height)。
二,RadioButton(如需完整的代码,请留言评论)
在RN中控制一个View动态改变需要使用到state,这里定义一个state变量selected来记录RadioButton是否被选中,并且可以默认选中某一个,为true为选中状态,false为未选中状态:(如需完整的代码,请留言评论)
1 this.setState({
2 selectedIndex: nextProps.selectedIndex//从RadioGroup组件传入
3 })
state变量和动态控制一个组件的改变,但是组件改变之前仍然可能会显示一些东西,这些东西用props来控制,而且可以用这些props定义一些默认的属性,例如我们可以定义默认的颜色等:
1 RadioGroup.defaultProps = {
2 size: defaultSize,
3 thickness: defaultThickness,
4 color: defaultColor,
5 highlightColor: null,
6 }
在使用时我们可能会给这个RadioButton添加style属性,例如单选按钮的宽,高颜色等,以及选中的小圆点颜色,宽,高等等等,这个是在外面设置的,在内部我们同样会设置style属性
1 getRadioStyle(){
2 return {
3 height: this.context.size,
4 width: this.context.size,
5 borderRadius: this.context.size / 2,
6 borderWidth: this.context.thickness,
7 borderColor: this.props.isSelected && this.props.activeColor?this.props.activeColor:this.context.color,
8 }
9 }
10
11 getRadioDotStyle(){
12 return {
13 height: this.context.size / 2,
14 width: this.context.size / 2,
15 borderRadius: this.context.size / 4,
16 backgroundColor: this.props.color || this.props.activeColor,
17 }
18 }
给最外层的View添加TouchableWithoutFeedback组件,添加点击事件以及是否可点击状态:
1 <View style={{opacity: this.props.disabled?0.4:1}}>
2 <TouchableWithoutFeedback
3 disabled={this.props.disabled}//是否可点击
4 onPress={() => this.context.onSelect(this.props.index, this.props.value)}//选中事件
5 >
6 {children}
7 </TouchableWithoutFeedback>
8 </View>
选中之后的样式选择:(如需完整的代码,请留言评论)
1 isSelected(){
2 if(this.props.isSelected)
3 return <View style={this.getRadioDotStyle()}/>
4 }
三,RadioGroup(如需完整的代码,请留言评论)
使用RadioButton大部分情况是多个共同使用,而且只能有一个被选中,android中就有这样的组件,但是在RN中没有找到,其实这个也很容易实现,原理是通过RadioGroup来生成多个RadioButton并且持有这些RadioButton的引用,当一个被选中的时候把其他的置为不选中(如需完整的代码,请留言评论)。
1 if(nextProps.selectedIndex != this.prevSelected){
2 this.prevSelected = nextProps.selectedIndex
3 this.setState({
4 selectedIndex: nextProps.selectedIndex
5 })
6 }
使用RadioGroup时给这个RadioButton传递多个即可,然后RadioGroup通过数组来创建RadioGroup,因为同样要指定RadioButton的样式,所以在外部使用时直接把style的各种样式和属性一并传递给RadioGroup,RadioGroup在创建RadioButton时把这些样式属性再传递给RadioButton(如需完整的代码,请留言评论):
1 <View style={this.props.style}>
2 {radioButtons}
3 </View>
4 RadioGroup.childContextTypes = {
5 onSelect: PropTypes.func.isRequired,
6 size: PropTypes.number.isRequired,
7 thickness: PropTypes.number.isRequired,
8 color: PropTypes.string.isRequired,
9 activeColor: PropTypes.string,
10 highlightColor: PropTypes.string,
11 }
获取选中事件的函数(如需完整的代码,请留言评论):
1 onSelect(index, value){
2 this.setState({
3 selectedIndex: index
4 })
5 if(this.props.onSelect)
6 this.props.onSelect(index, value)
7 }
四,使用实例(如需完整的代码,请留言评论)
已实现的样列(如需完整的代码,请留言评论):
组件代码实现:
1 <RadioGroup
2 style={{ backgroundColor: '#fff' }}
3 onSelect={(index, value) => this.onSelect(index, value)}
4 selectedIndex={this.state.selectedIndex}
5 >
6 {UsersAddress.map((model, i) => {
7
8 return (
9 <RadioButton
10 key={i}
11 value={model}
12 selectedIndex={1}
13 style={{ backgroundColor: '#fff', marginBottom: 12, borderBottomColor: '#e4e4e4', borderBottomWidth: 12 }}>
14 <Text>张三</Text>
15 </RadioButton>
16 <RadioButton
17 key={i}
18 value={model}
19 selectedIndex={1}
20 style={{ backgroundColor: '#fff', marginBottom: 12, borderBottomColor: '#e4e4e4', borderBottomWidth: 12 }}>
21 <Text>李四</Text>
22 </RadioButton>
23 <RadioButton
24 key={i}
25 value={model}
26 selectedIndex={1}
27 style={{ backgroundColor: '#fff', marginBottom: 12, borderBottomColor: '#e4e4e4', borderBottomWidth: 12 }}>
28 <Text>王二</Text>
29 </RadioButton>
30 </RadioGroup>
1 onSelect(index, value) {
2 //alert(JSON.stringify(value))
3 //this.openAduice()
4 this.setState({
5 text: `Selected index: ${index} , value: ${value}`,
6 addressId: value.id
7 })
8 }