Reputation: 2523
I have a super specific case here that is kind of tripping me up on how the math needs to work out to get this to work
I have this card rendered on the page
Which is rendered with these styles...
-------- main card --------
position: 'absolute',
left: 0,
right: 0,
bottom: 0,
height,
shadowColor: "#455B63",
shadowOffset: {
width: 0,
height: 0,
},
shadowOpacity: 0.33,
shadowRadius: 16,
borderBottomLeftRadius: 12,
borderBottomRightRadius: 12
-------- content view --------
backgroundColor: '#fff',
paddingVertical: 14,
paddingHorizontal: 20,
height: height * 2
With this animation attached to it...
Animated.spring(this.state.placeCard,{
toValue: {x: 0, y: deviceHeight - placeCardClosedHeight},
duration: 350,
}).start();
The content view has this animation state set in the state
new Animated.ValueXY({x: 0, y: -(Math.round(deviceHeight / 2) - 160)})
And I'm trying to get it to animate to this layout
The panhandler I have set up for handle the overall card styles is this
this._placeCardPanResponder = PanResponder.create({
onMoveShouldSetPanResponderCapture: (evt, gestureState) => gestureState.dx != 0 && gestureState.dy != 0,
onPanResponderGrant: (evt, gestureState) => {
this.setState({
placeCardTopOffset: this.state.placeCard.__getValue().y
})
},
onPanResponderMove: (evt, gestureState) => {
let y = gestureState.dy;
const { placeCardTopOffset } = this.state;
if (y + placeCardTopOffset <= 0) {
y = 0
} else if (y + placeCardTopOffset >= deviceHeight - placeCardClosedHeight) {
y = deviceHeight - placeCardClosedHeight
} else {
y = y + placeCardTopOffset;
}
this.state.placeCard.setValue({x: 0, y});
},
onPanResponderRelease: (evt, gestureState) => {
if (gestureState.dy < 0) {
if (this.state.placeCard.__getValue().y > 0) {
Animated.timing(
this.state.placeCard,
{
toValue: {x: 0, y: 0},
duration: 175,
}
).start();
}
}
if (gestureState.dy > 0) {
if (this.state.placeCard.__getValue().y < deviceHeight - placeCardClosedHeight) {
Animated.timing(
this.state.placeCard,
{
toValue: {x: 0, y: deviceHeight - placeCardClosedHeight},
duration: 175,
}
).start();
}
}
}
});
When the card is full height on the page the content view would be animated something like this
Animated.timing(
this.state.placeCardContent,
{
toValue: {x: 0, y: 0},
duration: 175,
}
).start();
I have a snack setup to show this off
If you click on the image you will see the intended animation but if you drag you will see how the dragging is being handled. Where I am having issues is with trying to figure out the math related to animating that content view while the main view is being dragged.
https://snack.expo.io/B1lhq5Rb4
Upvotes: 0
Views: 682
Reputation: 2523
I was neglecting to remember the fact that react-native
's Animated
API has a .interpolate()
function which was designed for this vary task.
Here is the code to make this work...
<Animated.View style={{...style.placeCardContent, transform: [{
translateX: 0
},{
translateY: this.state.placeCard.y.interpolate({
inputRange: [0, deviceHeight - placeCardClosedHeight],
outputRange: [0, -(Math.round(deviceHeight / 2) - 160)]
})
}]}}>
You can see this working in this snack example
https://snack.expo.io/@jordanr/carddrag
Upvotes: 2