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 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 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 }