我得到了一个使用 PanResponder 与 React Native API 的动画相结合的组件。我的组件的代码:
import React, { Component } from 'react';
import { Animated, PanResponder } from 'react-native';
import { SVG } from '../';
import { Icon, LockContainer, StatusCircle } from './styled';
class VehicleLock extends Component {
state = {
pan: new Animated.ValueXY({ x: 9, y: 16 }),
};
componentWillMount() {
this.animatedValueY = 0;
this.minYValue = 16;
this.maxYValue = 175;
this.state.pan.y.addListener((value) => {
this.animatedValueY = value.value;
});
this.panResponder = PanResponder.create({
onStartShouldSetPanResponderCapture: () => true,
onMoveShouldSetPanResponderCapture: () => true,
onPanResponderGrant: (evt, gestureState) => {
this.state.pan.setOffset({ x: 0, y: 0 });
// this.state.pan.setOffset(this.state.pan.__getValue());
this.state.pan.setValue({ x: 9, y: this.minYValue });
},
onPanResponderMove: (evt, gestureState) => {
// deltaY: amount of pixels moved vertically since the beginning of the gesture
let newY = gestureState.dy;
if (newY < this.minYValue) {
newY = this.minYValue;
} else if (newY > this.maxYValue) {
newY = this.maxYValue;
}
Animated.event([null, {
dy: this.state.pan.y,
}])(evt, {
dy: newY,
});
},
onPanResponderRelease: (evt, gestureState) => {
let newY = this.minYValue;
const releaseY = gestureState.dy;
if (releaseY > 83) {
newY = this.maxYValue;
}
Animated.spring(this.state.pan, {
toValue: {
x: 9,
y: newY,
},
}).start();
},
});
}
componentWillUnmount() {
this.state.pan.x.removeAllListeners();
this.state.pan.y.removeAllListeners();
}
render() {
const customStyles = {
...this.state.pan.getLayout(),
position: 'absolute',
zIndex: 10,
transform: [
{
rotate: this.state.pan.y.interpolate({
inputRange: [this.minYValue, this.maxYValue],
outputRange: ['0deg', '180deg'],
}),
},
],
};
return (
<LockContainer>
<SVG icon="lock_open" width={16} height={21} />
<Animated.View
{...this.panResponder.panHandlers}
style={customStyles}
>
<StatusCircle>
<Icon>
<SVG icon="arrow_down" width={23} height={23} />
</Icon>
</StatusCircle>
</Animated.View>
<SVG icon="lock_closed" width={16} height={21} />
</LockContainer>
);
}
}
export default VehicleLock;
正如您在我的代码中看到的,我使用边界对 Y 值进行动画处理。它必须保持在某些值之间的框中。一旦用户释放拖动并且它超过最大 Y 值的一半,它就会动画到最大值。
这可以正常工作,但在第二次交互时我想反转该操作。因此,它必须上涨,而不是下跌。不幸的是,发布后 Y 值会重置。
正如您在我的代码中的注释中所看到的,我知道移动是基于增量的,因此自交互开始以来移动的 Y 值。这个伟大的评论对此进行了解释PanResponder snaps Animated.View back to original position on second drag 。
在第二个输入时,元素弹回到顶部。这是预期的行为。正如 @jevakallio 在他的评论中所述,您可以在 onPanResponderGrant
中重置偏移量中的值。当我这样做时(已注释掉),元素会重置值,但在第二次交互时,它将在容器外部进行动画处理。因此,在这种情况下,0
是 maxYValue
,它会将容器外部的 175
动画到底部。
如何制作一个反转的动画,从外面回到顶部?我似乎不太明白这一点。提前致谢!
最佳答案
根据Panresponder docs onPanResponderGrant
应指示手势的开始。因此,如果您此时设置 this.state.pan.setOffset
和 this.state.pan.setValue
,它将在每个手势开始时重置。尝试在 onPanResponderGrant
中查看 console.log,看看会发生什么。
此外,实现 PanResponder 的父组件或包装组件可能会干扰您的 PanResponder。这可能是解决问题的另一个良好起点。
来自 PanResponder 文档:
onPanResponderGrant: (evt, gestureState) => {
// The gesture has started. Show visual feedback so the user knows
// what is happening!
// gestureState.d{x,y} will be set to zero now
},
关于javascript - 在第二个输入上 react native 动画 PanResponder 反转,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50511918/