ReactNative 自定义封装Radio单选组件

前言

由于RN官网并没有提供Radio单选组件,所以需要自己封装通用的单选组件

实现效果图:
单列布局

image

两列布局

image

传值方式

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;

猜你喜欢

转载自blog.csdn.net/gongch0604/article/details/81191392