我正在建立一个音乐播放器,我专注于进度条。 我能够对滑动手势做出反应,但我无法限制手势的移动距离。
这是我迄今为止所做的。我把所有东西都减少到了minumal:
constructor(props) {
super(props);
this.state = {
pan: new Animated.ValueXY()
};
}
componentWillMount() {
this._panResponder = PanResponder.create({
onMoveShouldSetResponderCapture: () => true,
onMoveShouldSetPanResponderCapture: () => true,
onPanResponderGrant: (e, gestureState) => {
// Set the initial value to the current state
let x = (this.state.pan.x._value < 0) ? 0 : this.state.pan.x._value;
this.state.pan.setOffset({ x, y: 0 });
this.state.pan.setValue({ x: 0, y: 0 });
},
onPanResponderMove: Animated.event([
null, { dx: this.state.pan.x, dy: 0 },
]),
onPanResponderRelease: (e, { vx, vy }) => {
this.state.pan.flattenOffset();
}
});
}
render() {
let { pan } = this.state;
// Calculate the x and y transform from the pan value
let [translateX, translateY] = [pan.x, pan.y];
// Calculate the transform property and set it as a value for our style which we add below to the Animated.View component
let imageStyle = { transform: [{ translateX }, { translateY }] };
return (
<View style={styles.container}>
<Animated.View style={{imageStyle}} {...this._panResponder.panHandlers} />
</View>
);
}
这里有一张图片显示问题所在。
因此,一旦达到限制(左侧和右侧),这个想法就是停止继续前进。我尝试检查是否_value < 0
,但它没有工作,因为它似乎是一个偏移,而不是一个位置。
任何帮助都将不胜感激。
答案 0 :(得分:2)
onPanResponderMove: (e, gestureState)=> {
this.state.pan.x._value > 0 ? null : Animated.event([
null,
{dx: this.state.pan.x, dy: this.state.pan.y},
])(e, gestureState)
},
答案 1 :(得分:1)
我正在尝试做类似的事情;我想拥有它,以便您可以拉开页面的一部分然后释放,然后回到原来的位置。
我的解决方法是这样:
panResponder = PanResponder.create({
onMoveShouldSetPanResponderCapture: (e, { dx }) => {
// This will make it so the gesture is ignored if it's only short (like a tap).
// You could also use moveX to restrict the gesture to the sides of the screen.
// Something like: moveX <= 50 || moveX >= screenWidth - 50
// (See https://facebook.github.io/react-native/docs/panresponder)
return Math.abs(dx) > 20;
},
onPanResponderMove: (e, gestureState) => (
// Here, 30 is the limit it stops at. This works in both directions
Math.abs(gestureState.dx) > 30
? null
: Animated.event([null, { dx: this.animatedVal }])(e, gestureState)
),
onPanResponderRelease: (e, { vx, dx }) => {
// Here, abs(vx) is the current speed (not velocity) of the gesture,
// and abs(dx) is the distance traveled (not displacement)
if (Math.abs(vx) >= 0.5 || Math.abs(dx) >= 30) {
doSomeAction();
}
Animated.spring(this.animatedVal, {
toValue: 0,
bounciness: 10,
}).start();
},
});
答案 2 :(得分:1)
您可以插补您的插值,而不是让动画在边界消失 带有y = x的Animated.Value,但将其固定到您的宽度。
return (
<View style={styles.container}>
<Animated.View
style={{
transform: [{
translateX: this.state.pan.x.interpolate({
inputRange: [0, trackWidth ],
outputRange: [0, trackWidth ],
extrapolate: 'clamp'
})
}],
}}
{...this._panResponder.panHandlers}
/>
</View>
);
这是更深入的示例:https://github.com/olapiv/expo-audio-player/blob/master/src/AudioSlider.js
答案 3 :(得分:1)
一个棘手的问题是,虽然我无法将图标移动到该限制之外,但 pan.x 值确实超出了限制限制,尽管您看不到它。然后,当您想将其移回时,您不知道需要多少次滑动才能将其移回。这可能是一个细微差别。
我的解决方案是:
onPanResponderGrant: () => {
console.log("pan responder was granted access!")
pan.setOffset({
x: (pan.x._value>xMax)? xMax : (pan.x._value<xMin)? xMin: pan.x._value,
y: (pan.y._value>yMax)? yMax : (pan.y._value<yMin)? yMin: pan.y._value,
});
},
然后,也可以在下面的console.log pan.x._value进行复查。
onPanResponderRelease: () => {
pan.flattenOffset();}
我发现这对我自己的项目很有帮助。注意只能使用 pan.x_value 不能使用 pan.x。 就我而言,我还使用了 useMemo 而不是 useRef,因此可以重置限制,这是我从 React Native's panResponder has stale value from useState?
中学到的答案 4 :(得分:0)
在另一个问题上有一个类似问题的解决方案:Here
可以根据您的需求重新调整
const DRAG_THRESHOLD = /*configure min value*/
const DRAG_LIMIT = /*configure max value*/
onPanResponderMove: (e, gesture) => {
if ( (Math.abs( gesture.dy ) > DRAG_THRESHOLD) &&
(Math.abs( gesture.dy ) < DRAG_LIMIT ) )
{
return Animated.event([
null, {dx: 0, dy: pan.y}
]) (e, gesture)
}
},
这不是我的答案,因此,我建议您单击链接以查看进一步的说明,如果喜欢,请对原始海报进行投票! :)我试图做同样的事情,它为我工作!希望对您有帮助。
P.S。我发现,依赖检查动画值而不是手势值的其他解决方案有时会卡住。