欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

React Native 滑动组件

程序员文章站 2022-05-30 20:57:22
...

一、先放上效果图镇楼
React Native 滑动组件

二、封装这种组件,算是常规操作,练的多了,就有思路了。这里简单的说下封装的思路

  • 动态创建中间的指示文本,一般是根据数组的内容来创建这些文本,有些时候,在创建好了之后我们还需要去获得这些组件的引用方便丢相应的接口出去,典型的如果,为每个控件绑定点击事件,在原生android与ios还好,创建好组件对象之后,再用一个对象数据将其存入起来,之后从这个数组中获取即可,但是在React 中这种似乎行不通(如果有人知道这样可行的话,麻烦底下留言,我们一起交流,交流)react Native 中对 对象的引用是通过 this.refs.创建对象时定义的引用字符串,然后再去操作这个对象公开函数,刚开始很难适应这种获取引用的方式(现在好像也没适应,经常写成原生的引用方式)
  • 动画效果
    其实rn 的动画效果在使用上有点类似ios 的风格,为了达到外边框移动的效果,这里只需要改变这个外边框的位置即可,这个位置我们可以用一个动画来控制它的左边距
    代码为:
Animated.timing(this.state.indexViewMarginLeft, {
            toValue: i * screenWidth / this.txtRefList.length,
            duration: 500,
            easing: Easing.linear
        }).start(()=>{
            this.props.onButtonClick && this.props.onButtonClick(i);  //动画结束的回调
        });
  • 如果为了有更高的可扩展性,可以将类似选中/未选中的颜色,文本大小、颜色待属性传出去。

最后放出全部源码,不然有人估计要开始骂娘了


import React from "react";
import {Button, View, Text, StyleSheet,Dimensions,
    Image,TextInput,ListView,Alert,Animated,Easing,
    TouchableOpacity} from 'react-native';
import PropTypes from 'prop-types';

let screenWidth = Dimensions.get('window').width;
let screenHeight = Dimensions.get('window').height;

export default class SlideButton extends React.Component{

    static propTypes = {
        onButtonClick: PropTypes.func,
        txtArray:PropTypes.array,
    };

    constructor(){
        super();
        this.state = {
            indexViewMarginLeft:new Animated.Value(0),
            activityTxtColor:'#4394F1',
            inactiveTxtColor:'gray',
            selecIndex:1,

        };
        this.textList = [];
        this.txtRefList = [];

    };

    moveLeftAnim(){
        Animated.timing(this.state.indexViewMarginLeft, {
            toValue: 20,
            duration: 800,
            easing: Easing.linear
        }).start();
    };

    moveRightAnim(){
        Animated.timing(this.state.indexViewMarginLeft, {
            toValue: screenWidth / 2 + 10,
            duration: 800,
            easing: Easing.linear
        }).start();
    };

    componentDidMount() {
        this.state.indexViewMarginLeft.addListener(({value})=> {
            // if(value === 20){
            //
            //     this.refs.index1.setNativeProps({
            //         style: {
            //             color: this.state.activityTxtColor,
            //         }
            //     });
            //     this.refs.index2.setNativeProps({
            //         style: {
            //             color: this.state.inactiveTxtColor,
            //         }
            //     });
            //     this.props.onButtonClick && this.props.onButtonClick(1);
            //
            // }else if(value === (screenWidth / 2 + 10)){
            //     this.refs.index2.setNativeProps({
            //         style: {
            //             color: this.state.activityTxtColor,
            //         }
            //     });
            //     this.refs.index1.setNativeProps({
            //         style: {
            //             color: this.state.inactiveTxtColor,
            //         }
            //     });
            //     this.props.onButtonClick && this.props.onButtonClick(2);
            // }
        });
    }

    componentWillUnMount() {
        this.state.indexViewMarginLeft.removeAllListeners();
    }

    render(){
        let{txtArray} = this.props;
        // txtArray.map(function(value,key){
        //     console.log('84--------:'+key+" value:"+value);
        // });
        // console.log('83----------:'+txtArray.length);
        // let testView = this.buileTxt(txtArray);
        // console.log('88----------'+testView);
        return(
            <View style = {{flex:1}}>

                <View style = {{width:'100%',height:60,flexDirection:'row'}}>
                   
                    {this.buileTxt(txtArray)}

                </View>

                {/*滚动视图*/}
                <Animated.View pointerEvents={'none'} style = {{height:50,width:screenWidth / txtArray.length,
                    borderWidth:2,borderColor:'#4394F1',
                    borderRadius:22.5,marginTop:-55,marginLeft:this.state.indexViewMarginLeft}}>

                </Animated.View>

            </View>
        )

    }

    buileTxt(array){

        for(let i = 0; i < array.length; i ++){
            let view = <Text style = {[styles.slideButtonStyle,{
                color:i === 0? this.state.activityTxtColor:this.state.inactiveTxtColor,backgroundColor:'#1235F5',}]}
                             ref={ (refName) => {
                                 this.txtRefList[i] = refName
                             }}
                             key={i+"2019"}
                             onPress = {() =>this.startAnim(i)}>
                {array[i]}
            </Text>
            this.textList.push(view);
        }

        return this.textList;
    };

    startAnim(i){

       for(let k = 0 ; k < this.txtRefList.length; k ++){
            if(k === i){
                this.txtRefList[i].setNativeProps({
                    style: {
                        color: this.state.activityTxtColor
                    }
                });
            }else{
                this.txtRefList[k].setNativeProps({
                    style: {
                        color: this.state.inactiveTxtColor,
                    }
                });
            }
        }

        Animated.timing(this.state.indexViewMarginLeft, {
            toValue: i * screenWidth / this.txtRefList.length,
            duration: 500,
            easing: Easing.linear
        }).start();

    };
}

const styles = StyleSheet.create({

    container: {
        flex:1,
        backgroundColor:'#F5F5F5',
        flexDirection:'column',
    },

    slideButtonStyle:{
        flex:1,
        height:60,
        textAlignVertical:'center',
        lineHeight:60,
        textAlign:'center',
        alignItems:'center',
    },


});
  • 使用方式:
    把下这段代码放入你的render函数中
buildSlideButtonView(){
        let buttonParmas = {
            txtArray:['我的分润模板','下级代理分润模板',"分润模板"],
        };
        return (
            <SlideButton
                {...buttonParmas}

                onButtonClick={(index)=>this.onSildeButtonClick(index)}
            />
        );
    };

render函数中调用上述方法方式为:

render(){
        return(
            <View style = {{flex:1}}>

                {/*<View style = {{width:'100%',height:60,flexDirection:'row'}}>*/}
                    {/*<Text style = {[styles.slideButtonStyle,{marginLeft:20,marginRight:10,color:this.state.activityTxtColor,}]}*/}
                          {/*ref = "index1"*/}
                          {/*onPress = {() =>this.moveLeftAnim()}>*/}
                            {/*我的分润模板*/}
                    {/*</Text>*/}

                    {/*<Text style = {[styles.slideButtonStyle,{marginLeft:10,marginRight:20,color:this.state.inactiveTxtColor}]}*/}
                          {/*ref = "index2"*/}
                          {/*onPress = {() =>this.moveRightAnim()}>*/}
                        {/*下级代理分润模板*/}
                    {/*</Text>*/}

                {/*</View>*/}

                {/*/!*滚动视图*!/*/}
                {/*<Animated.View style = {{height:50,width:screenWidth / 2 - 30,*/}
                    {/*borderWidth:2,borderColor:'#4394F1',*/}
                    {/*borderRadius:22.5,marginTop:-55,marginLeft:this.state.indexViewMarginLeft}}>*/}

                {/*</Animated.View>*/}
                {this.buildSlideButtonView()}



            </View>
        )

    }
  • 友情提示,不要忘记了引入(引入的是你封装的这个组件的路径),类似在你的文件头部,作下述操作
    import SlideButton from ‘…/…/uikit/slideButton/SlideButton’;