React Native 双滑块滑动条

import React, { Component } from 'react';
import {
    View,
    PanResponder,
    StyleSheet,
    Text,
    Dimensions,
    Animated,
    Easing
} from 'react-native';

/* 数据相关: 
 * 
 */
// const labels = ['0', '100', '200', '300', '400', '600', '1000', '不限'];
const labels = ['0', '200', '400', '600', '1000', '不限'];

/* 尺寸转换方法
 * _px: 以750位基准的转屏幕
 * _pos: 以屏幕为基准的转750
 */
const dw = Dimensions.get('window').width;
const ratioDeps750 = dw / 750;
const _px = function getRpx(value) {
    return Math.floor(value * ratioDeps750);
}
const _pos = function getPos(value) {
    return Math.floor(value / ratioDeps750)
}

/* 尺寸相关 
 * excludeWidth: 距离屏幕左右边界的距离,不触发点击滑动等事件的区域
 * unitWidth: 每一个单位的总宽度,有效区域等分后的宽度
 * labelWidth: 每一个单位的有效的点击宽度
 * sliderWidth: 滑块的宽度
 * sliderInitialLeft: 第一个滑块的left
 */
const excludeWidth = 75;
const unitWidth = (750 - excludeWidth * 2) / labels.length; //100
const labelWidth = unitWidth - 20; // 两个标签核心之间间隙 40
const sliderWidth = 60;
const halfUnitWidth = unitWidth / 2; // slider:halfUnitWidth - sliderWidth / 2; line:halfUnitWidth


const duration = 300;
const easing = Easing.linear;

export default class App extends Component {
    constructor(props) {
        super(props)
        let leftBoundaryForLeft = 0;
        let rightBoundaryForLeft = 0;
        let validPosForLeft = 0;
        let leftBoundaryForRight = 0;
        let rightBoundaryForRight = 0;
        let validPosForRight = 0;
        this.state = {
            leftIndex: 0,
            rightIndex: 0,
            leftPos: new Animated.Value(0),
            rightPos: new Animated.Value(0)
        }

        this._leftSliderPanResponder = PanResponder.create({
            onStartShouldSetPanResponder: (evt, gestureState) => true,
            onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
            onMoveShouldSetPanResponder: (evt, gestureState) => true,
            onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
            onPanResponderTerminationRequest: (evt, gestureState) => true,
            onShouldBlockNativeResponder: (evt, gestureState) => true,
            onPanResponderGrant: (evt, gestureState) => {
                // 左边界
                leftBoundaryForLeft = excludeWidth + halfUnitWidth;
                // 右边界
                rightBoundaryForLeft = this.state.rightIndex * unitWidth + excludeWidth + halfUnitWidth;
                validPosForLeft = _pos(gestureState.x0)
            },
            onPanResponderMove: (evt, gestureState) => {
                //手势中心点
                let centerX = _pos(gestureState.moveX)
                if (centerX >= leftBoundaryForLeft && centerX <= rightBoundaryForLeft - unitWidth) {
                    this.state.leftPos.setValue(centerX - excludeWidth);
                    validPosForLeft = centerX;
                    let posIndex = Math.floor((validPosForLeft - excludeWidth) / unitWidth);
                    this.setState({
                        leftIndex: posIndex
                    })
                }
            },
            onPanResponderRelease: (evt, gestureState) => {
                let posIndex = Math.floor((validPosForLeft - excludeWidth) / unitWidth);
                this.setPos({ leftIndex: posIndex })
            },
            onPanResponderTerminate: (evt, gestureState) => {

            },

        });
        this._rightSliderPanResponder = PanResponder.create({
            onStartShouldSetPanResponder: (evt, gestureState) => true,
            onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
            onMoveShouldSetPanResponder: (evt, gestureState) => true,
            onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
            onPanResponderTerminationRequest: (evt, gestureState) => true,
            onShouldBlockNativeResponder: (evt, gestureState) => true,
            onPanResponderGrant: (evt, gestureState) => {
                // 左边界
                leftBoundaryForRight = this.state.leftIndex * unitWidth + excludeWidth + halfUnitWidth;
                // 右边界
                rightBoundaryForRight = 750 - excludeWidth - halfUnitWidth;
                validPosForRight = _pos(gestureState.x0)
            },
            onPanResponderMove: (evt, gestureState) => {
                //手势中心点
                let centerX = _pos(gestureState.moveX)
                if (centerX >= leftBoundaryForRight + unitWidth && centerX <= rightBoundaryForRight) {
                    this.state.rightPos.setValue(centerX - excludeWidth);
                    validPosForRight = centerX;
                    let posIndex = Math.floor((validPosForRight - excludeWidth) / unitWidth);
                    this.setState({
                        rightIndex: posIndex
                    })
                }
            },
            onPanResponderRelease: (evt, gestureState) => {
                let posIndex = Math.floor((validPosForRight - excludeWidth) / unitWidth);
                this.setPos({ rightIndex: posIndex })
            },
            onPanResponderTerminate: (evt, gestureState) => {

            },
        });
        this._viewPanResponder = PanResponder.create({
            onStartShouldSetPanResponder: (evt, gestureState) => true,
            onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
            onMoveShouldSetPanResponder: (evt, gestureState) => true,
            onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
            onPanResponderTerminationRequest: (evt, gestureState) => true,
            onShouldBlockNativeResponder: (evt, gestureState) => true,
            onPanResponderGrant: (evt, gestureState) => {

            },
            onPanResponderMove: (evt, gestureState) => {

            },
            onPanResponderRelease: (evt, gestureState) => {
                if (gestureState.moveX) {
                    return;
                }
                let x = _pos(gestureState.x0);
                if ((x - excludeWidth) % unitWidth < (unitWidth - labelWidth) / 2 || (x - excludeWidth) % unitWidth > unitWidth - (unitWidth - labelWidth) / 2) {
                    console.log('无效点')
                    return;
                }
                let posIndex = Math.floor((x - excludeWidth) / unitWidth);

                let { leftIndex, rightIndex } = this.state;
                let leftPos = leftIndex * unitWidth + halfUnitWidth;
                let rightPos = rightIndex * unitWidth + halfUnitWidth;

                // 距离左边的点更近
                if (Math.abs(x - excludeWidth - leftPos) <= Math.abs(x - excludeWidth - rightPos)) {
                    this.setPos({ leftIndex: posIndex === rightIndex ? posIndex - 1 : posIndex })
                } else {
                    this.setPos({ rightIndex: posIndex === leftIndex ? posIndex + 1 : posIndex })
                }
            },
            onPanResponderTerminate: (evt, gestureState) => {

            },

        });
    }

    render() {
        let { leftPos, rightPos, leftIndex, rightIndex } = this.state;
        return (
            
                
                    
                        
                            {labels.map((item, index) => {
                                return  rightIndex ? '#898989' : '#3F70C1' }}>{item}
                            })}
                        
                        
                            
                            
                        
                    
                    
                    
                
                {leftIndex}
                {rightIndex}
            
        );
    }
    componentDidMount() {
        this.setPos({ leftIndex: 0, rightIndex: labels.length - 1 })
    }
    setPos({ leftIndex, rightIndex }) {
        if (leftIndex >= 0) {
            Animated.parallel([
                Animated.timing(this.state.leftPos, {
                    toValue: leftIndex * unitWidth + halfUnitWidth,
                    duration,
                    easing,
                })
            ]).start(() => {
                this.setState({
                    leftIndex: leftIndex
                })
            })
        }
        if (rightIndex >= 0) {
            Animated.parallel([
                Animated.timing(this.state.rightPos, {
                    toValue: rightIndex * unitWidth + halfUnitWidth,
                    duration,
                    easing,
                }),
            ]).start(() => {
                this.setState({
                    rightIndex: rightIndex
                })
            })
        }
    }
}

const styles = StyleSheet.create({
    container: {
        height: _px(180),
        backgroundColor: '#fff'
    },
    content: {
        backgroundColor: '#fff',
        height: _px(180),
        position: 'relative',
        marginHorizontal: _px(excludeWidth),
        marginVertical: _px(30),
        height: _px(120),
    },
    pan: {
        backgroundColor: '#fff'
    },
    labels: {
        height: _px(60),
        flexDirection: 'row',
        justifyContent: 'space-around',
        alignItems: 'center'
    },
    label: {
        width: _px(labelWidth),
        textAlign: 'center',
    },
    lines: {
        height: _px(60),
        justifyContent: 'center',
    },
    line: {
        position: 'absolute',
        backgroundColor: '#ddd',
        height: _px(4),
        left: _px(halfUnitWidth),
        right: _px(halfUnitWidth)
    },
    hl_line: {
        position: 'absolute',
        backgroundColor: '#3F70C1',
        height: _px(4),
    },
    slider: {
        width: _px(sliderWidth),
        height: _px(sliderWidth),
        resizeMode: 'contain',
        position: 'absolute',
        top: _px(90),
        transform: [{
            translateX: -_px(sliderWidth / 2),
        }, {
            translateY: -_px(sliderWidth / 2),
        }]
    }
});
const images = {
    slider: require('./img/slider.png')
}

你可能感兴趣的:(React Native 双滑块滑动条)