React Native - How to start another animation conditionally - react-native

I want to create my own loader using animation, my idea is using scale to handle it, so the step should be like:
show an image scale from (n) to 1 for the first time
check if conditional is accepted or not
if conditional accepted, show an image scale from 1 to (n)
I can achieve 1st condition, but when i try 2nd and 3rd condition, the animation start in a blink of eye,
anyone can help me how to fix this?
here's the code i've tried:
//animation function
playAnimation(){
this.setState({onLoad:true})
this._load.setValue(0)
this._scale.setValue(0)
Animated.timing(this._load, {
toValue: 100,
useNativeDriver: true,
duration:1000
}).start(()=>{
setTimeout(() => {
Animated.timing(this._scale, {
toValue: 100,
useNativeDriver: true,
duration:1000
}).start(()=>this.setState({onLoad:false}));
}, 2000);
});
onLoad = this._load.interpolate({
inputRange: [0, 50, 75, 100],
outputRange: [10, 1, 1.4, 1],
})
imageScale = this._scale.interpolate({
inputRange: [20, 35, 70],
outputRange: [1.2, 1, 20],
})
}
//on render
<Animated.Image
style={{
resizeMode:'contain',
position:'absolute',
zIndex:1,
width:width/2,
height:200,
transform:[{scale:this.state.onLoad?onLoad:imageScale}]
}}
source={{uri: "https://www.knittedhome.com/communities/5/004/012/872/235/images/4628207884.jpg"}}
/>
and the result:

How your code works right now is somewhere in your code, you're calling PlayAnimation().
PlayAnimation() will:
start and complete first animation
Wait 2 sec
start and complete second animation
What you're doing in your Animated.Image is setting the transforms to different values. This doesn't start or stop the animation, just tells Animated.Image what value to set transform to.
What you should do
Use one Animated.Value to keep track of the scale. Assign that value to the Animated.Image transform.
Write two Animation functions:
scaleDown, call this where you're currently calling PlayAnimation
scaleUp, use your onLoad conditional to execute this in render or somewhere appropriate.

Related

How interpolate works? REACT NATIVE ANIMATED

I kind of new using animation, im using react native reanimated to create some animations, but i really dont understand how interpolate works, the input range, output range, the animation that i want its inside a scrollview, each item should has its own Animated.View, so the first one will be 100% width and the rest will be like 20%, i want to create this design:
for now my code is this:
const animatedWidth = useAnimatedStyle(() => {
const width_ = interpolate(
cardWidth,
[0,1, 2],
[4, 4, 5],
);
return {
width: width_,
};
});
return (
<>
<Animated.ScrollView horizontal = {true}>
{
extras.map((extra) => {
return (
<>
<Animated.View style = {[{height: 220, margin: 5}, animatedWidth]}>
<ImageBackground
source = {require("../assets/images/hawai.jpeg")}
style = {{width: "100%", height: "100%"}}
imageStyle = {{borderRadius: 30
}}>
[![</Animated.View][2]][2]>
)}
}
<Animated.ScrollView>
)
and this is the result:
i can scroll and it "works" and i want to make it work like the first design, the first full width and the others 20% width, but i really dont understand the interpol and the inputRange to make them appears, if someone knows and can explain to me in simple works really greateful, searched for videos and documentation but like i said still dont understand, thanks :)

How to do series/parallel animation in react-native-reanimated 2?

I'm looking for the equivalent of Animated.sequence and Animated.parallel from react-native. So far from the docs for v2, I could only see the withSequence function that changes the value of only on value and therefore the style of only one component in series.
What I was looking for was to trigger animations in two different components, either in series or in parallel.
For parallel, it seems changing values in statements one after another worked. Correct me if I'm wrong.
// these will run in parallel
val1Shared.value = withTiming(50);
val2Shared.value = withTiming(100);
But for series, I need to have each animation inside a useTiming callback. Which leads to kind of callback hell.
val1Shared.value = withTiming(50, undefined, () => {
val2Shared.value = withTiming(100);
});
Please help with the best practices in achieving this with reanimated 2.
Thanks.
I think there is no way of doing it like in Animated.
This library requires you to think a different way. If you want you run two animations (each one for a separate view) using interpolation, you can use a single shared value and a sufficient interpolation config.
Let's assume (according to your example) that you have two views you want to animate. The first animation is from 0 to 50, the second one is from 0 to 100.
Let's also assume you're transforming an X axis (I don't know what's your case, but it's going to be very similar) and we count the animation progress from 0 to 1, and both views will animate for the same period of time.
Initialize the shared value:
const animation = useSharedValue(0);
And do sth like this (of your choice):
animated.value = withTiming(1, { duration, easing });
For the first view, your transformation will look like this:
const animatedStyles1 = useAnimatedStyle(
() => ({
transform: [
{
translateX: interpolate(animation.value, [0, 0.5, 1], [0, 50, 50]),
},
],
}),
[mode, rectSize]);
and for the second one, like this:
const animatedStyles2 = useAnimatedStyle(
() => ({
transform: [
{
translateX: interpolate(animation.value, [0, 0.5, 1], [0, 0, 100]),
},
],
}),
[mode, rectSize]);
Now the explanation.
For the first view, we only work for the half of progress from the whole animation, so we from 0 to 0.5 we'll animate from 0 to 50. then, for the reset of the progress we'll stay in the same place (this is called a dead zone), to from 0.5 to 1 value of the progress does not change (50 to 50).
Now, for the second view, we wait for the progress to be in half, so from 0 to 0.5 we don't do anything (0 to 0). Then, when the progress is in half, we animate the view from 0 to 150.
In general, that way you can orchestrate the whole thing using just a single shared value.
Here you can find more info about the interpolation. The docs is from the react-native's Animated, but the idea is the same.
Good luck!

how can I stop the wheel of fortune to particular point using Animated API in React Native?

I'm developing wheel of fortune where I want the wheel to iterate four times while spinning, and stop to a particularly given value. All I want is to spin the wheel four times and stop to a particular slice. I'm thinking below code can work my idea.
Animated.loop(
Animated.timing(this._angle, {
toValue: 920,
duration: 5000,
}),//.start();
{
iterations: 1
}
).start();
I'm using angle as value. My formula to get the 'toValue' is "targetAngle * 4". This works but I want to decelerate the spinning in its last iterate just like Animated.decay() does. Is there any better idea to resolve this issue?
you can do
const onPress = () => {
Animated.timing(RotateAnimeted, {
toValue: 6,
duration: 1000,
}).start();
};
const Rotate = RotateAnimeted.interpolate({
inputRange: [0, 1, 2, 3, 4, 5, 6],
outputRange: [
"0deg",
"360deg",
"720deg",
"840deg",
"940deg",
"1020deg",
"1080deg",
],
});
You can change the values to get the result you want
I did an example at the expo
Attaches a gif image

How can I Animate instantly in React native

I am starting animated using 'onPanResponderMove' to move the animated view whenever the user is holding down the button
onPanResponderMove: (evt, gestureState) => {
if (withinbounds(gestureState.moveX, xOffset + buttonSize, xOffset + buttonSize * 2)) {
this.setState({y: this.state.y + 1});
Animated.timing(
this.state.layerOffset,
{toValue: {x: 0, y: (this.state.y * gridSize}, easing: Easing.in(Easing.ease)},
).start();
}
}
Which is being used to set the offset of a view
<Animated.View style={{position: 'absolute', left: this.state.layerOffset.x, top: this.state.layerOffset.y}}>
<Grid />
</Animated.View>
However, the way this is currently working, the animated view will not move until The button is stopped being press, how can I make the animation start immediately, instead of waiting for the button to no-longer be pressed although this.state.y is continually updated.
When playing around with PanResponder the way to go is usually using Animated.event instead of Animated.timing. Here's some doc that might help you out.
When using Animated.timing you should provide a duration, which you haven't done in this case. The difference between the two is that Animated.timing will change a value over a certain period of time whereas Animated.event instantly sets the value which is what you want.

Creating a parallax image in React Native

I'm trying to create an animated "parallax" image in React-Native. I have a static background image and two individual images as an overlay. The goal is to create something similar to the image found on this website http://www.digitalhands.net/ or https://www.galaxia.co/. Where do I even start with this? Initially I'd be happy with it moving just on itself from left to right and etc. Afterwards I want to make it so that it would use the gyroscope to get the x and y values for animating the image.
A parallax effect consists of images moving in different speeds and in the same direction, such that the 'closer' an object is, the faster it moves, which creates the illusion of three dimensions.
To achieve this effect in react-native, you can use the Animated library to interpolate the position of one image as a fraction of the position of another.
For the sake of an example, let's assume you want the parallax effect in the vertical direction, and that all images are positioned at 0 vertically.
First, you would need an animated value in your component's state:
this.state = {
...
imagePos: new Animated.Value(0)
}
Then, for each Image style you can add a transform on its y axis:
<Animated.Image src={...} style={[firstImageStyle, {
transform: [{translateY: this.state.imagePos.interpolate({
inputRange: [0, 1],
outputRange: [0, 100]
})}]
}]}
<Animated.Image src={...} style={[secondImageStyle, {
transform: [{translateY: this.state.imagePos.interpolate({
inputRange: [0, 1],
outputRange: [0, 50]
})}]
}]}
Note the use of Animated.Image instead of Image to make the image animatable.
This would cause the first image to move horizontally between 0-100 dp when imagePos has values between 0 and 1, and the second image to move between 0-50 dp.
To change the value of the animated value you can use any of the functions in the Animated library (timing, spring, decay, etc.) or you can attach it to some native event.
The animated library documentation has much more detail.
As for the use of the gyroscope, I haven't gone into the details, but you can probably use react-native-sensors or react-native-motion-manager to get the values you need, and attach them to the animation.
By using a package like https://github.com/react-native-sensors/react-native-sensors I managed to get the x, y, z values of the phones position and animate an image with it.
constructor() {
super();
this.state = {
x: 0,
y: 0,
z: 0,
};
}
componentWillMount() {
// Normal RxJS functions
accelerationObservable
.subscribe(({x, y, z}) => this.setState({
x: x,
y: y,
z: z,
}));
}
render() { return (
<Image style={{left: this.state.x + this.state.y, top: this.state.z}}
source={require('image.png')}/>
)
}