React Native animations - translateX and translateY while scaling
I've solved this problem by using scale factor for positioning:
imageScale = new Animated.Value(1);
imageX = new Animated.Value(0);
imageX = new Animated.Value(0);
...
<Animated.Image source={item} style={[styles.image, {
transform:[
{scale: this.imageScale},
{translateX: Animated.divide(this.imageX,this.imageScale)},
{translateY: Animated.divide(this.imageY,this.imageScale)},
]
}]}/>
If you use interpolation, this looks a bit complicated but the idea remains the same:
transform: [
{
scale: this.animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [initialScale, 1]
})},
{
translateX: Animated.divide(
this.animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [startX, endX]
}),
this.animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [initialScale, 1]
})
)
}]
Like the user @ArneHugo pointed out in the comments, the non-linear movement can be solved by positioning the full-size container element and scaling another element within it.
The position of the element is not as expected, because the origin for the scale transform is the center point of the element. React Native doesn't (yet) support specifying the transform origin, but if the width and height of the scaled element are known in advance, it's easy to calculate the offset as follows:
const width = 100;
const height = 20;
const scale = {
transform: [
{
scale: this.animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [initialScale, 1]
})
}
]
};
const position= {
transform: [
{
translateX: this.animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [startX - (width / 2) - (width * initialScale / 2), endX]
})
},
{
translateY: this.animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [startY - (height / 2) - (height * initialScale / 2), endY]
})
}
]
};
return (
<Animated.View style={position}>
<Animated.View style={[styles.thing, scale]} />
</Animated.View>
);