美文网首页
ReactNative学习之自定义Button

ReactNative学习之自定义Button

作者: BlainPeng | 来源:发表于2016-12-11 15:17 被阅读3116次

    不管是Android还是ios,Button控件都在这两个原生开发中都已经被封装好了,我们可以直接使用。但是在RN中并没有直接提供这种组件给我们,而是给我们提供了一个可点击的组件:Touchable系列(如TouchableOpacity, TouchableHighlight等)。那么今天我们就一起来学习封装属于我们自己的Button。看一下我们的效果图

    CustomButton.gif CustomButton_Android.gif

    上面的效果图中有三个Button,若不封装的话,我们就肯定会写很多重复代码,这对于一个面向对象的程序员来说肯定是不能接受的。好了,那我们就一起来实现封装的代码吧。若不熟悉Touchable系列组件的,可以先看看我之前写的文章。

    实现步骤

    • step 1 先封装一个可点击的button

        _renderTouchableHighlight(selectedColor, type,style) {
      
            return (
                <TouchableHighlight
                    underlayColor={selectedColor}
                    onPress={this._onPress}
                    style={[styles.container, type,style, this.state.disable && {backgroundColor: this.props.disableColor}]}
                    disabled={this.state.disable}
                >
                    <Text style={this.props.textStyle}>{this.props.text}</Text>
      
                </TouchableHighlight>
            );
        }
        
        
        
        _renderTouchableOpacity(type,style) {
      
            return (
                <TouchableOpacity
                    onPress={this._onPress}
                    style={[styles.container, type, style]}
                    disabled={this.state.disable}
                >
                    <Text style={this.props.textStyle}>{this.props.text}</Text>
      
                </TouchableOpacity>
            );
        }
      

    这里用两个方法来渲染不同类型的button,其实它们的不同之处在于:当Button被点击的时候,button需要呈现出什么样的状态来进行视觉交互。RN已经给Opacity类型的button设置了selected状态,但我们若需要自己定义selected按钮状态的话,就需要使用TouchableHighlight类型的。

    方法中的selectedColor用来判断使用者是选择何种类型的button,若传来了selectedColor,那么就作为TouchableHighlight的underlayColor。对于整个button长什么样,由使用者去定制,不过我们可肯定的是,button的文字肯定是居中的,所以设置了styles.container,代码如下:

    container: {
        justifyContent: 'center',
        alignItems: 'center',
        overflow: 'hidden'  //这个属性定义溢出元素内容区的内容会如何处理,内容会被修剪,并且其余内容是不可见的。
    },
    

    方法中第二个参数type是用来决定用户需要什么样的button,是实心,空心或者仅是text。

    static _setDifferentButtonStyle(buttonColor, buttonRadius, buttonType, borderWidth) {
    
        if (buttonType == "normal") {
    
            return CustomButton._setDifferentStyle(buttonColor, buttonRadius, buttonColor);
    
        } else if (buttonType == 'stroke') {
    
            return CustomButton._setDifferentStyle('transparent', buttonRadius, buttonColor, borderWidth);
    
        } else if (buttonType == 'text') {
    
            return CustomButton._setDifferentStyle('transparent', 0, 'transparent');
        }
    }
    
    static _setDifferentStyle(backgroundColor, borderRadius, borderColor, borderWidth) {
    
        return {
            backgroundColor: backgroundColor,
            borderRadius: borderRadius,
            borderColor: borderColor,
            borderWidth: borderWidth
        };
    }
    

    上面代码中,可以根据使用者传过来的buttonType类型来返回对应的button样式;至于第三个参数style,是使用者设置button时传过来的具体的样式,我们可以直接拿来用。

    • step 2 传递点击事件

    Touchable系列中有个onPress方法,这是用来处理点击事件的。我们不可能把外面传过来的事件在这个类中去处理,而是需要使用者自己处理。那如何做了?也就是事件的传递了,另外一种说法就是回调。在最上面代码中,有看到onPress={this._onPress},那么这个this._onPress到底是谁了?

    _onPress() {
        if (this.props.onPress) {
            
            this.props.onPress();
        }
    }
    

    从上面的代码中可以看出,最终是调到传过来的onPress方法。不过我们若直接这样调的话,肯定会报错。为什么?因为这个方法是我们自己定义的,但没有像组件的生命周期方法一样,在一个组件被创建时就已经被初始化了。所以,我们需要将我们自己定义的方法与初始时进行绑定。初始化操作我们一般放在构造方法中进行。

    constructor(props) {
        super(props);
        this._onPress = this._onPress.bind(this);
    }
    
    • step 3 防重复点击

    网络请求数据一般是耗时操作,为了防止用户多次点击button去请求数据,我们还需要设置在做耗时操作时,不能让button变得可点击,并且给出视觉交互。那如何来实现了?我们可以通过状态的改变来决定是否可以点击。有两种实现方式:

    1、对外提供两个方法,让使用者通过拿到我们自定义button的实例来调用这个暴露出去的方法,从而达到点击与不可点击的切换

    2、我们可以将某个改变点击状态的方法传给使用者进行回调,让使用者决定什么时候可改变button的点击状态。

    第一种相当来说比较简单,我们来使用第二种方式。

    constructor(props) {
        super(props);
        this._onPress = this._onPress.bind(this);
        this._enable = this._enable.bind(this);
        this._disable = this._disable.bind(this);
    
        this.state = {
            disable: false
        }
    }
    
    _onPress() {
        if (this.props.onPress) {
            this._disable();
            this.props.onPress(this._enable);
        }
    }
    
    _enable() {
        this.setState({
            disable: false
        });
    };
    
    _disable() {
        this.setState({
            disable: true
        });
    };
    

    我们通过一个状态值来保存button的可点击状态,在button被点击时,马上将这个button置为不可点击,至于什么时候可以点击,我们将enable方法回调给了使用者,由使用者决定。如上面所说,我们自定义的方法都必须先在构造方法中进行初始化。

    • step 4 设置属性类型和默认值

    我们自定义的属性需要什么类型,使用者并不知道,所以我们需要声明我们自定义属性的类型,可以通过PropTypes,并且还可以强制用户必须传哪些属性。

    //属性类型
    CustomButton.propTypes = {
    
        text: PropTypes.string.isRequired,
        textStyle: Text.propTypes.style,
        buttonType: PropTypes.oneOf(['normal', 'stroke', 'text']).isRequired,
        selectedColor: PropTypes.string,
        onPress: PropTypes.func,
        buttonColor:PropTypes.string,
        buttonRadius:PropTypes.number,
        borderWidth:PropTypes.number,
    };
    
    //属性默认值
    CustomButton.defaultProps = {
    
        borderWidth: 1
    };
    

    最后是整个类的渲染

    render() {
        
        //这里是将props中属性进行解构,es6语法,可查看阮一峰的《ES6标准与入门》
        let {selectedColor, buttonColor, buttonRadius, buttonType, borderWidth, style}=this.props;
        let type = CustomButton._setDifferentButtonStyle(buttonColor, buttonRadius, buttonType, borderWidth);
    
        if (selectedColor) {
            {
                return this._renderTouchableHighlight(selectedColor, type, style);
            }
        } else {
            {
                return this._renderTouchableOpacity(type, style);
            }
        }
    }
    
    • step 5 进行测试

        <View style={styles.container}>
                <CustomButton
                    text="确定"
                    buttonColor="red"
                    buttonRadius={20}
                    buttonType="normal"
                    textStyle={styles.textStyle}
                    style={styles.customButton}
                    selectedColor="green"
                    disableColor="yellow"
                    onPress={(callback)=> {
                        setTimeout(()=> {
      
                            callback();
      
                        }, 3000);
                    }}
                />
                <CustomButton
                    text="确定"
                    buttonColor="red"
                    buttonRadius={20}
                    buttonType="stroke"
                    textStyle={styles.textStyle}
                    style={styles.customButton}
                    selectedColor="green"
                    disableColor="yellow"
                    onPress={(callback)=> {
                        setTimeout(()=> {
      
                            callback();
      
                        }, 3000);
                    }}
                />
                <CustomButton
                    text="确定"
                    buttonColor="red"
                    buttonRadius={20}
                    buttonType="text"
                    textStyle={styles.textStyle}
                    selectedColor="green"
                    disableColor="yellow"
                    style={{marginTop:20}}
                    onPress={(callback)=> {
                        setTimeout(()=> {
      
                            callback();
      
                        }, 3000);
                    }}
                />
            </View>
      

    好了,自定义button就封装完了以及学习了自定义一个组件需要做哪些事。这里面稍微有一点难度的就是方法的传递进行回调。在java中是不允许方法作为参数传递的。不过,在java中不能干的事,在js中可以干是非常常见的。我们今天做的button主要是文字,其实还可以对其进行拓展,那就是这个button为image时,那个比较简单,有兴趣的朋友可以进一步进行封装。

    本人目前对于RN也还是处于学习的阶段,若在写文章时出现了错误或者代码可以优化时,请各位朋友不吝告知啊!

    完整代码

    相关文章

      网友评论

          本文标题:ReactNative学习之自定义Button

          本文链接:https://www.haomeiwen.com/subject/oerpmttx.html