Reputation: 1561
I got a component using the PanResponder in combination with Animated from React Native API's. The code of my component:
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;
As you can see in my code I animate the Y value with a boundary. It has to stay in a box between certain values. As soon users release the drag and it's over half of the max Y value it's animated to the max value.
This works without any problems, but on the second interaction I would like to reverse the action. So instead of going down, it has to go up. Unfortunately on release the Y value resets.
As you can see in the comment in my code I know the movement is based on the delta, so the moved Y value since the interaction started. This is explained in this great comment PanResponder snaps Animated.View back to original position on second drag.
Although I don't know how to fix it. Here you can see my current behaviour:
On the second input the element snap back to the top. Which is expected behavior. As @jevakallio states in his comment, you can reset the values in the offset in onPanResponderGrant
. As I do that (commented out), the element resets the values, but on second interaction it will animate outside the container. So in that case 0
is the maxYValue
and it animates 175
outside the container to the bottom.
How can I make a reversed animated outside back to the top? I don't seem to get this. Thanks in advance!
Upvotes: 0
Views: 1785
Reputation: 11
According to Panresponder docs the onPanResponderGrant
should indicate the start of a gesture. So if you set the this.state.pan.setOffset
and the this.state.pan.setValue
at this point, it will reset with the start of every gesture. Try a console.log in the onPanResponderGrant
and see what happens.
Also, a parent or wrapping component implementing the PanResponder could be interfering with your PanResponder. This could be another good starting point to troubleshoot.
From the PanResponder docs:
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
},
Upvotes: 1