反应本机pan响应器设置边界,有时无法正常工作

时间:2019-05-28 07:50:47

标签: react-native

我正在尝试使用本机PanResponder创建一个自定义水平范围滑块 在用户平移时,我用Animated.View值更新了Animated.ValueXY,当用户点击左边框或右边框时,我想以某种方式停止移动此Animated.View,但是当用户滑动时该视图不会在边界上停留得更快,并且超出了限制。

我该如何解决?

这是完整的代码,

import React, { useRef, useEffect } from 'react'
import {
    Platform,
    View,
    PanResponder,
    Animated,
  Dimensions,
  StyleSheet
} from 'react-native';
import PropTypes from 'prop-types';

function usePanResponders({ parentWidth, reverse, width, values, onMoving}) {
    const endXPos = parentWidth - width;
    const _values = useRef({...values}).current;
    const pan = useRef(new Animated.ValueXY({...values})).current

    useEffect(() => {
        pan.addListener((values) => {
            _values.x = values.x
        });
        return () => {
            pan.removeAllListeners();
        }
    }, [])

    return [useRef(PanResponder.create({
        onMoveShouldSetPanResponder: () => true,
        onMoveShouldSetPanResponderCapture: (_, { dx }) => Math.abs(dx) > 20,
        onPanResponderGrant: () => {
            if(!reverse) {
                console.log(reverse)
                pan.setOffset({x: _values.x, y: _values.y});
                pan.setValue({x: 0, y: 0});
            }
        },
        onPanResponderMove: (e, gestureState) => {
            const isMovingLeft = gestureState.dx > 0;
            // this is how i stops right border
            if((_values.x >= endXPos) && isMovingLeft) return null;
            // left border
            if(!isMovingLeft && _values.x <= 0) return null;

            return Animated.event(
                [ null,
                {dx: pan.x}
                ], 
                {listener: null}
            )(e, gestureState);
        },
        onPanResponderRelease: () => onMoving(_values)
    })).current, pan];
}

function useCss({width, height, color}) {
   return [
    Platform.select({
        ios: {
            zIndex: 999,
            position: 'absolute',
        },
        android: {
            position: 'absolute',
        }
    }),
    {
        backgroundColor: color,
        width,
        height
    }
   ]
}

function AsyncDraggable({x, y, width, height, color, parentWidth, reverse, onDragEnd}) {
    const [position, item] = useCss({width, height, color})
    const onMoving = (v) => {
        console.log(v)
    }
    const values = {x, y}
    console.log('Rendering...')
    const [panresponder, pan] = usePanResponders({parentWidth, reverse, width, pan, values, onMoving})
    return (
        <View style={{...position}}>
                <Animated.View
                    {...panresponder.panHandlers}
                    style={[pan.getLayout()]}>
                    <View
                        style={{...item}}
                    >       
                    </View>
                </Animated.View>
            </View>
    )
}

AsyncDraggable.prototype = {
    width: PropTypes.number,
    height: PropTypes.number,
    color: PropTypes.string,
    parentWidth:PropTypes.number.isRequired,
    onDragEnd: PropTypes.func,
    onMove: PropTypes.func,
      x:PropTypes.number,
      y:PropTypes.number
}

AsyncDraggable.defaultProps = {
    x : 0,
    y : 0,
    reverse : false,
    onMove: () => {}
}

const margin = {
    top: 10,
    bottom: 20,
    left: 50,
    right: 15
};

const screenWidth = Dimensions.get('window').width;

function Scroller({width, height,  panWidth}){
    const computedWidth = width - (margin.left + margin.right);
    const _height = height || 70

    return (
        <View style={{
            marginLeft: margin.left,
            marginRight: margin.right,
            marginTop: margin.top,
            width: computedWidth, 
            overflow: 'hidden',
            height, 
            backgroundColor: 'rgba(255,255,255,0.04)'}}>
            <AsyncDraggable x={10} color={'yellow'} parentWidth={computedWidth} width={panWidth} height={_height}/>
        </View>
    )
}

Scroller.prototype = {
    height: PropTypes.number,
    width: PropTypes.number,
}

Scroller.defaultProps = {
    height: 70,
    width: screenWidth,
    panWidth: 60
}

export default class App extends React.Component {
  render() {
    return (
      <View style={styles.container}>
        <Scroller/>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    padding: 8
  }
});

如代码所示

if((_values.x >= endXPos) && isMovingLeft) return null;

if(!isMovingLeft && _values.x <= 0) return null;

这就是我设法阻止左右移动的方式。但是当用户快速移动时它没用。

0 个答案:

没有答案