How can I animate the Y Value to 100 when the updated prop changes from false to true? Thanks!
For instance, say the user panned the Animated.View so that the Y Value is now 300 and then pressed a button. When they pressed that button, I want to animate the Y Value to 100. Afterward the user can pan the Animated.View Y Value to wherever they want.
import React, { useRef, useState } from 'react';
import { StyleSheet } from 'react-native';
import { PanGestureHandler, PinchGestureHandler, RotationGestureHandler, State } from 'react-native-gesture-handler';
import Animated from 'react-native-reanimated';
const {
add,
block,
call,
concat,
cond,
debug,
event,
eq,
greaterThan,
multiply,
onChange,
set,
timing,
useCode,
Value,
} = Animated;
const styles = StyleSheet.create({
area: {
position: 'absolute',
top: 0,
zIndex: 999,
},
box: {
backgroundColor: 'lightblue',
height: 200,
position: 'absolute',
top: 0,
width: 200,
},
});
const Move = ({ updated }) => {
const rotationRef = useRef();
const panRef = useRef();
const pinchRef = useRef();
const offsetX = new Value(0);
const offsetY = new Value(0);
const offsetR = new Value(0);
const offsetZ = new Value(1);
const [X] = useState(new Value(0));
const [Y] = useState(new Value(0));
const [R] = useState(new Value(0));
const [Z] = useState(new Value(1));
const onPan = event([
{
nativeEvent: ({ translationX: x, translationY: y, state }) => block([
set(X, add(x, offsetX)),
set(Y, add(y, offsetY)),
cond(
eq(state, State.END),
[
set(offsetX, add(offsetX, x)),
set(offsetY, add(offsetY, y)),
],
),
]),
},
]);
const onRotate = event([
{
nativeEvent: ({ rotation: r, state }) => block([
set(R, add(r, offsetR)),
cond(
eq(state, State.END),
[set(offsetR, add(offsetR, r))]
),
]),
},
]);
const onZoom = event([
{
nativeEvent: ({ scale: z, state }) => block([
cond(eq(state, State.ACTIVE), set(Z, multiply(z, offsetZ))),
cond(eq(state, State.END), [set(offsetZ, multiply(offsetZ, z))]),
]),
},
]);
return (
<>
<PanGestureHandler
minDist={10}
ref={panRef}
onGestureEvent={onPan}
onHandlerStateChange={onPan}
simultaneousHandlers={[rotationRef, pinchRef]}
>
<Animated.View style={styles.area}>
<PinchGestureHandler
onGestureEvent={onZoom}
onHandlerStateChange={onZoom}
ref={pinchRef}
simultaneousHandlers={[rotationRef, panRef]}
>
<Animated.View>
<RotationGestureHandler
onGestureEvent={onRotate}
onHandlerStateChange={onRotate}
ref={rotationRef}
simultaneousHandlers={[pinchRef, panRef]}
>
<Animated.View
style={[
styles.box,
{
transform: [
{ translateX: X },
{ translateY: Y },
{ rotate: concat(R, 'rad') },
{ scale: Z },
],
}
]}
/>
</RotationGestureHandler>
</Animated.View>
</PinchGestureHandler>
</Animated.View>
</PanGestureHandler>
</>
);
};
export default Move;
Hi @noobvim,
try creating some Value and using it as a flag:
const shouldAnimate = new Value(0);
const onClick = () => shouldAnimate.setValue(1);
// somewhere in your animation code
cond(shouldAnimate,
set(shouldAnimate, 0)
set(X, 100)
);
Does it answer your question?
Kind of...
The code below does not work. However, if I change const shouldAnimate = new Value(0) to const shouldAnimate = useState(new Value(0)), then it does work. Do you know why that would be?
Also, when switching shouldAnimate between 0 and 1, how can I transition smoothly between set(Y, add(y, offsetY)) and set(Y, 100)? Thanks again! I really appreciate your help.
const shouldAnimate = new Value(0);
useEffect(() => {
shouldAnimate.setValue(updated ? 1 : 0);
}, [updated]);
const onPan = event([
{
nativeEvent: ({ translationX: x, translationY: y, state }) => block([
cond(
shouldAnimate,
[
set(Y, add(y, offsetY)),
],
[
set(Y, 100),
],
),
cond(
eq(state, State.END),
[
set(offsetX, add(offsetX, x)),
set(offsetY, add(offsetY, y)),
],
),
]),
},
]);
@noobvim It happens because in FunctionComponent, using direct assignment:
const shouldAnimate = new Value(0)
you recreate shouldAnimated each render. This does not happen when using useState - new Value(0) is only initial value there.
In other words, shouldAnimated_fromRender1 === shouldAnimated_fromRender2 equals true for useState, but false for direct assignment.
Thanks @DrRefactor that was helpful.
@noobvim, adding to the @DrRefactor answer, you can use useRef/useMemo to preserve old reference between rerenders. You can look at #786 to check out how you can do it.