ReactNative 自定義封裝Radio單選元件
阿新 • • 發佈:2018-12-27
前言
由於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;