前言
由于RN官网并没有提供Radio单选组件,所以需要自己封装通用的单选组件
实现效果图:
单列布局
两列布局
传值方式
1、使用 dataOption={datas} 属性传值 必填属性
datas数据示例:
[{
selecteId: 13,
content: <TextInput style={styles.input} placeholder="请输入电话号码" />,
disabled: false
},{
selecteId: 14,
content: "Banana",
disabled: false
},
{
selecteId: 15,
content: "Orange",
disabled: false
}]
注意:content传值可以是字符串也可以是DOM,如果传入的是DOM结构样式自定义就行
2、options属性包含以下参数 必填属性
id:对应数组对象中唯一标识的名字id
value:对象中具体的name或者传入的DOM
disabled:是否可以勾选
<Radio
dataOption={this.state.data}
options={{
id: "selecteId",
value: "content",
disabled: "disabled"
}}
/>
自定义属性介绍
属性:
initStyle:自定义行内样式(包括背景颜色,行高等)无默认值
txtColor:定义单选按钮对应文字样式(默认值:#414141)
activeTxtColor:定义单选按钮选中时的文字样式 默认值:#ff552e
noneColor:定义disabled时的文案样式 默认值:#ACA899
图片都有默认值,展示上图有
seledImg:被选中时单选按钮图片链接
selImg:默认的单选按钮图片链接
selnoneImg:disabled时的单选按钮图片链接
labelStyle:定义按钮文字样式
selectedValue:默认选中的单选按钮 如果不设置就是默认无选中值
isPeer:布局方式 false一行一列的布局方式,true一行两列的布局方式,默认false
事件
onValueChange:点击选中时的传值
接收两个参数,一个是按钮ID,一个是按钮name
onValueChange={(id, item) => this.setState({ initId: id, initItem: item })}
把选中的按钮set到父组件的state中,如果需要默认选中的按钮,还需要自己在state中指定一个初始选中的按钮
调用
<Radio
dataOption={this.state.data}
options={{
id: "selecteId",
value: "content",
disabled: "disabled"
}}
onValueChange={(id, item) => this.setState({ initId: id, initItem: item })}
selectedValue={this.state.initId}
txtColor="#333"
activeTxtColor="#000"
innerStyle={styles.initStyle}
labelStyle={styles.labelStyle}
rowHeight={35}
isPeer={true}
/>
完整代码:
组件radio.js
/**
* @author gongchenghui
* @version 2018.07.24
* @description 单选按钮组件 支持自定义样式和布局方式
*/
import React, { Component } from "react";
import { View, StyleSheet, TouchableHighlight, Text, Image } from "react-native";
const Dimensions = require("Dimensions");
const width = Dimensions.get("window").width;
const height = Dimensions.get("window").height;
const styles = StyleSheet.create({
seltedImgs: {
width: 20,
height: 20,
marginRight: 8
},
content: {
flex: 1,
flexDirection: "row",
alignItems: "center"
},
parent: {
flexDirection: "row",
flexWrap: "wrap"
}
});
export default class RadioModal extends Component {
constructor(props) {
super(props);
this.state = {
clicked: true,
radioInit: this.props.radioInit,
indexa: this.props.selectedValue == undefined ? "0" : this.props.selectedValue
};
}
click(id, item) {
this.setState({ indexa: id });
this.props.onValueChange(id, item);
}
componentDidMount() {
const indexInit = this.props.selectedValue == undefined ? "0" : this.props.selectedValue;
this.setState({
indexa: indexInit
});
//this.props.onValueChange(indexInit)
}
createInner(child, index, props) {
const disabled = props ? child[this.props.options.disabled] : child.props.disabled;
const childC = props ? child[this.props.options.value] : child.props.children;
const values = props ? child[this.props.options.id] : child.props.value;
const hightlight = props
? this.state.indexa == child[this.props.options.id]
: this.state.indexa == child.props.value;
return (
<Radio
child={childC}
index={index}
value={values}
key={index}
initStyle={this.props.innerStyle}
txtColor={this.props.txtColor}
activeTxtColor={this.props.activeTxtColor}
noneColor={this.props.noneColor}
onclick={this.click.bind(this)}
hightlight={hightlight}
disabled={disabled}
seledImg={this.props.seledImg}
selImg={this.props.selImg}
selnoneImg={this.props.selnoneImg}
labelStyle={this.props.labelStyle}
rowHeight={this.props.rowHeight}
isPeer={this.props.isPeer}
/>
);
}
render() {
const that = this;
return (
<View {...this.props.style} style={this.props.isPeer ? styles.parent : null}>
{!this.props.dataOption &&
React.Children.map(this.props.children, (child, index) =>
this.createInner(child, index)
)}
{this.props.dataOption &&
this.props.dataOption.map((item, index) => this.createInner(item, index, true))}
</View>
);
}
}
class Radio extends Component {
constructor(props) {
super(props);
}
click(id, item) {
if (this.props.disabled) {
return;
} else {
this.props.onclick(id, item);
}
}
render() {
let imgUrl = this.props.hightlight
? this.props.seledImg || require("./imgs/selted.png")
: this.props.selImg || require("./imgs/selt.png");
let imgUrlNone = this.props.selnoneImg || require("./imgs/seltnone.png");
return (
<TouchableHighlight
underlayColor="transparent"
style={[
this.props.initStyle,
{
width: this.props.isPeer ? width / 2 : width
}
]}
onPress={this.click.bind(this, this.props.value, this.props.child)}>
<View style={styles.content}>
{this.props.disabled &&
!this.props.hightlight && (
<Image source={imgUrlNone} style={styles.seltedImgs} />
)}
{this.props.disabled &&
this.props.hightlight && (
<Image source={imgUrl} style={styles.seltedImgs} />
)}
{!this.props.disabled && <Image source={imgUrl} style={styles.seltedImgs} />}
{typeof this.props.child == "string" ? (
<Text
style={[
{
color: this.props.disabled
? this.props.noneColor || "#ACA899"
: this.props.hightlight
? this.props.activeTxtColor || "#ff552e"
: this.props.txtColor || "#414141"
},
this.props.labelStyle
]}>
{this.props.child}
</Text>
) : (
<View>{this.props.child}</View>
)}
</View>
</TouchableHighlight>
);
}
}
父组件调用:Home.js
import React, { Component, PropTypes } from "react";
import {
StyleSheet,
Text,
ScrollView,
Image,
Alert,
TextInput,
View,
TouchableOpacity
} from "react-native";
import ToastMsg from "./../component/toast/Toast.native";
import Toast from "./../component/toast/index";
import Radio from "./../component/radio/radio";
const styles = StyleSheet.create({
flex: {
flex: 1,
marginTop: 65
},
listItem: {
height: 40,
marginLeft: 10,
marginRight: 10,
borderBottomWidth: 1,
borderBottomColor: "#ddd",
justifyContent: "center"
},
listItemFont: {
fontSize: 16
},
initStyle: {
backgroundColor: "#fff",
paddingHorizontal: 15,
height: 50
},
labelStyle: {
fontSize: 14
},
input: {
borderWidth: 1,
borderColor: "#ccc",
borderRadius: 4,
height: 30
}
});
class Home extends Component {
constructor(props) {
super(props);
this.state = {
text: "",
textarea: "",
initId: 14,
initItem: "Banana",
data: [
{
selecteId: 13,
content: <TextInput style={styles.input} placeholder="请输入电话号码" />,
disabled: false
},
{
selecteId: 14,
content: "Banana",
disabled: false
},
{
selecteId: 15,
content: "Orange",
disabled: false
},
{
selecteId: 16,
content: "Watermelon",
disabled: true
},
{
selecteId: 17,
content: "Grape",
disabled: false
}
]
};
}
getFormData = () => {
let radioId = this.state.initId;
};
render() {
const { navigate } = this.props.navigation;
return (
<ScrollView>
<Radio
dataOption={this.state.data}
options={{
id: "selecteId",
value: "content",
disabled: "disabled"
}}
onValueChange={(id, item) => this.setState({ initId: id, initItem: item })}
selectedValue={this.state.initId}
txtColor="#333"
activeTxtColor="#000"
innerStyle={styles.initStyle}
labelStyle={styles.labelStyle}
rowHeight={35}
isPeer={true}
/>
<TouchableOpacity onPress={this.getFormData.bind(this)}>
<Text>获取选中radio</Text>
</TouchableOpacity>
</View>
</ScrollView>
);
}
}
export default Home;