用react-native-svg简单实现兼容slider

emmmm,不多说了,代码贴下面,各位大佬自己参透吧~

import React, { PureComponent } from 'react'
import Svg, { Path, Circle, G } from 'react-native-svg'
import { View, PanResponder } from 'react-native'

let runNumber_change = 0;
export default class Slider extends PureComponent {
    static defaultProps = {
        min: 0, // 最小值
        max: 100, // 最大值
        width: 20,
        color: '#128BFC',
        backgroundColor: '#F5F5F5',
        curColor: '#ffffff'
    }

    constructor(props) {
        super(props)

        this._panResponder = PanResponder.create({
            // 要求成为响应者:
            onStartShouldSetPanResponder: () => true,
            onPanResponderGrant: this._handlePanResponderGrant,
            onPanResponderMove: this._handlePanResponderMove,
            onPanResponderTerminationRequest: () => true,
            onPanResponderRelease: this._handlePanResponderEnd,
            onPanResponderTerminate: this._handlePanResponderEnd,
        });

        this.state = {
            value: props.value || props.min,
            svgWidth: 0
        }
    }

    static getDerivedStateFromProps(nextProps, prevState) {
        //该方法内禁止访问this
        if (nextProps.value !== prevState.value) {
            //通过对比nextProps和prevState,返回一个用于更新状态的对象
            if (runNumber_change == 0) {
                return { value: nextProps.value }
            } else {
                return prevState
            }
        }
        //不需要更新状态,返回null
        return null
    }

    _handlePanResponderGrant = () => {
        /*
         * 记录开始滑动时的滑块值,用于后续值的计算
         */
        this._moveStartValue = this.getPointValue(this.getEndValue(), this.getStartValue(), this.state.value)
        runNumber_change = 1;
    };

    _handlePanResponderMove = (e, gestureState) => {
        const { min, max } = this.props || this.defaultProps
        let x = gestureState.dx
        let increment = x + this._moveStartValue
        increment = (increment - this.props.width / 2) / ((this.getEndValue() - this.getStartValue()) / max)
        increment = Math.round(increment)
        if (increment >= max) increment = max;
        if (increment <= min) increment = min;
        this.setState({ value: increment })
        this._fireChangeEvent('onChange');
    }

    _handlePanResponderEnd = (e, gestureState) => {
        if (this.props.disabled) {
            return;
        }
        this._fireChangeEvent('onComplete');
        runNumber_change = 0;
    }

    _fireChangeEvent = event => {
        if (this.props[event]) {
            this.props[event](this.state.value);
        }
    };

    _onLayout = (event) => {
        this.setState({ svgWidth: event.nativeEvent.layout.width })
    }

    getStartValue = () => {
        return this.props.width / 2
    }

    getEndValue = () => {
        return this.state.svgWidth - this.props.width / 2;
    }

    getPointValue = (endValue, start, value) => {
        const { max, min } = this.props || this.defaultProps
        let PointValue = ((endValue - start) / (max - min) * value) + this.props.width / 2
        if (PointValue <= start) {
            PointValue = start
        }
        if (PointValue >= endValue) {
            PointValue = endValue
        }
        return PointValue - this.props.width / 2
    }

    getCurValue = (pointValue) => {
        return pointValue + this.props.width / 2
    }

    render() {
        const {
            style,
            disabled
        } = this.props
        const start = this.getStartValue()
        const endValue = this.getEndValue()
        const pointValue = this.getPointValue(endValue, start, this.state.value)
        const curValue = this.getCurValue(pointValue)
        const width = this.props.width || this.defaultProps.width
        const color = this.props.color || this.defaultProps.color
        const backgroundColor = this.props.backgroundColor || this.defaultProps.backgroundColor
        const curColor = this.props.curColor || this.defaultProps.curColor
        const disabledColor = this.props.disabledColor || this.defaultProps.disabledColor
        return (
            <View onLayout={this._onLayout} style={[{ position: 'relative' }, style]}>
                {
                    this.state.svgWidth ?
                        <Svg height={width} width='100%'>
                            <G fill="none" stroke={backgroundColor}>
                                <Path strokeLinecap="round" strokeWidth={width} d={`M${start} ${width / 2} l${this.state.svgWidth - this.props.width} 0`} />
                            </G>
                            <G fill="none" stroke={disabled ? disabledColor : color}>
                                <Path strokeLinecap="round" strokeWidth={width} d={`M${start} ${width / 2} l${pointValue} 0`} />
                            </G>
                            {
                                disabled ?
                                    <Circle
                                        cx={curValue}
                                        cy={width / 2}
                                        r={width / 2 - (width / 100 * 10)}
                                        fill={curColor}
                                        stroke={5}
                                        strokeWidth={20}
                                        fillOpacity={1}
                                        strokeOpacity={1} /> :
                                    <Circle
                                        cx={curValue}
                                        cy={width / 2}
                                        r={width / 2 - (width / 100 * 10)}
                                        fill={curColor}
                                        stroke={5}
                                        strokeWidth={20}
                                        fillOpacity={1}
                                        strokeOpacity={1}
                                        {...this._panResponder.panHandlers} />
                            }
                        </Svg> : null
                }
            </View>
        )
    }
}

大概就是这样咯~ 功能比较简单 或许不会在所有场景都那么好用,原本也就是工作需要特意写的~走过路过的大佬欢迎留下宝贵意见,万分感谢!

上一篇:WPF系列教程(十八):范围控件——Slider、ProgressBar滑块、进度条


下一篇:Vue 滑块解锁组件(无UA算法校验)