Expo React Native - How to animate an icon onpress? - react-native

I want an icon to bounce (or other animations) when I click the icon. Im trying to implement it looking at the example on expo but nothing works and I also have problems understanding:
interpolate : how do I know what numbers I need for inputRange&outputRange? I cannot find any info about this.
I also dont really get how to use animatedStyles in order to achieve the bounce effect.
Ive looked up tutorials but I still dont get it. An help would be really great. Thank you!!
import { Ionicons } from '#expo/vector-icons';
const AnimatedIconComponent = Animated.createAnimatedComponent(Ionicons);
const AnimatedIcon = () => {
let bounce = new Animated.Value(60);
const animate = () => {
bounce.setValue(0);
Animated.timing(bounce,
{
toValue: 100,
duration: 1200,
easing: Easing.bounce,
useNativeDriver: true
})
.start()
}
const size = bounce.interpolate({
inputRange: [0, 1],
outputRange: [0, 80]
});
const animatedStyles = [
styles.icon,
{
bounce,
width: size,
height: size
}
];
return (
<View>
<TouchableHighlight onPress={()=> animate()}>
<AnimatedIconComponent
name="checkmark-circle-outline"
size={64} style={animatedStyles}
/>
</TouchableHighlight>
</View>
)
};
export default AnimatedIcon;

Related

Set reanimated values back to original after click

I have made a bit of re-usable animation code. It works great but I an unsure if it is possible to get the animations back to their original values after a button is pressed easily.
The only way I can think of it to use useShared Values to store all the before and after values and set them as required but this would involve alot of values but because the animations have already ran, there must be a way to just take them back to their original start?
The code I am using for the animations is : -
EntryAnimation.js
import React, { useEffect } from 'react';
import Animated, {
useAnimatedStyle,
useSharedValue,
useDerivedValue,
interpolate,
withDelay,
withTiming,
withSpring,
Easing,
} from 'react-native-reanimated';
export const EntryAnimation = ({
children,
index,
rotateV,
scaleV,
offsetXV,
offsetYX,
}) => {
const play = useSharedValue(play);
const progress = useDerivedValue(() => {
return play.value
? withDelay(50 * (index ?? 0), withSpring(1, { duration: 350 }))
: 0;
});
useEffect(() => {
play.value = play;
}, []);
const animatedStyle = useAnimatedStyle(() => {
// const opacity = interpolate(progress.value, [0, 1], [0, 1]);
const translateY = interpolate(progress.value, [0, 1], [0, offsetYX]);
const translateX = interpolate(progress.value, [0, 1], [0, offsetXV]);
const rotate = interpolate(progress.value, [0, 1], [0, rotateV]);
const scale = interpolate(progress.value, [0, 1], [1, scaleV]);
return {
transform: [{ translateY }, { translateX }, { rotate }, { scale }],
};
});
return <Animated.View style={animatedStyle}>{children}</Animated.View>;
};
And to use on an element in my main code, I use :-
<EntryAnimation
index={1}
rotateV={0}
scaleV={0.8}
offsetXV={0}
offsetYX={-270}>
<Animated.Image
source={{ uri: item.poster }}
style={[styles.posterImage, { zIndex: 6 }]}
/>
</EntryAnimation>
I have tried using the code below but because its in a ternary statement I am getting errors?
{animStarted ? (
<EntryAnimation
index={1}
rotateV={0}
scaleV={0.8}
offsetXV={0}
offsetYX={-270}
>
) : (
<EntryAnimation
index={1}
rotateV={0}
scaleV={1}
offsetXV={0}
offsetYX={0}
>
)}
Any ideas?

React Native remove default State

When onPress then Element the code get the start position of the Element (Y_POSITION) and move/animated from the Y_POSITION to 200 (POSITION_INTERPOLATE). The code working good but there is one detail that needs to be changed in order to be perfected.
The detail is that onPress first move superfast from 0 (or any var is default in state useState(0) ) and after move to Y_POSITION and next to 200.
I try to change useState(0) with useState(null or false or true) but nothing change.
Do you have any idea what to do?
I give the basic code for my question.
const [Y_POSITION, setY_POSITION] = useState(0);
const POSITION_ANIM = useRef(new Animated.Value(0)).current
const POSITION_INTERPOLATE = POSITION_ANIM.interpolate({
inputRange: [0, 1],
outputRange: [Y_POSITION, 200],
})
const onPress = () => {
newRef?.current?.measure( (fx, fy, width, height, px, py) => {
setY_POSITION(fy)
Animated.timing(
POSITION_ANIM,
{
toValue: 1,
duration: 500,
useNativeDriver: false
}
).start();
})
}
And an element with transform: [{ translateY: POSITION_INTERPOLATE }],

react-native-reanimated useSharedValue does not update in jest tests

I'm currently trying to figure out how to test reanimated 2 animations using useSharedValue.
What makes 0 sense to me is the example given from reanimated.
https://github.com/software-mansion/react-native-reanimated/blob/master/tests/SharedValue.test.js
If the button is supposed to increment its sharedValue by 1 every time you press it. Why would you write a test that shows it does NOT change???
I've tried it myself and yea, the value does not update itself.
I want to assert that the value has changed in my test:
ParallaxScrollView.tsx
const scrollY = useSharedValue(0);
const onScroll = useAnimatedScrollHandler((event) => {
scrollY.value = event.contentOffset.y;
});
return (
<Animated.Image
style={{height: scrollY}}
testID="header-image"
source={{ uri: headerImage }}
resizeMode="cover"
/>
)
ParallaxScrollView.test.tsx
const { getByTestId } = render(<ParallaxScrollView {...defaultProps} />);
const headerImage = getByTestId('header-image');
const content = getByTestId('parallax-content');
const eventData = {
nativeEvent: {
contentOffset: {
y: 100,
},
},
};
fireEvent.scroll(content, eventData);
expect(headerImage).toHaveAnimatedStyle({ height: 100 }); //Received is 0
useAnimatedScrollHandler uses react-native-gesture-handler to handle events but at this moment gesture-handler doesn't support events in tests yet, this is what I am working on. Look at this - https://github.com/software-mansion/react-native-gesture-handler/pull/1762
I think this will be available soon. If you want to be up to date, please open an issue in the Reanimated Github.

How Do You Create Multiple, Simultaneous and Identical Animations in React Native?

What Currently Happens
There is an image of a gun. You click the gun, an animation fires with a single bullet.
You click the gun again. The original bullet animation disappears and new bullet comes out of the gun.
What I Want to Happen
You click the gun multiple times and multiple bullets are seen animating. The original bullet does not go away until the animation has run its course.
Is this possible with React Native? Can you point me in the right direction?
Here's the snippet of the animation code if it helps...
import React from 'react';
import { View, Animated, Easing, Dimensions, Image } from 'react-native'
let animatedValue = new Animated.Value(0)
export let animateHappy = () => {
console.log('animate happy run')
animatedValue.setValue(0)
Animated.timing(
animatedValue,
{
toValue: 1,
duration: 800,
useNativeDriver: true,
easing: Easing.linear
}
)
.start()
}
export function HappyAnimation() {
let windowWidth = Dimensions.get('window').width
let windowHeight = (Dimensions.get('window').height)
const movingMargin = animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [0, (windowHeight/2.4)]
})
const movingXHappy = animatedValue.interpolate({
inputRange: [0, 1],
outputRange: [0, -90]
})
return (
<Animated.Image
source={require('./assets/happy.png')}
style={{
transform: [
{translateY: (movingMargin)},
{translateX: (movingXHappy)}
],
zIndex: 0,
marginLeft: 144,
marginTop: (windowHeight*.35),
height: 14,
width: 14,}}
/>
)
}
export default HappyAnimation
You need to instantiate, render, and trigger a new HappyAnimation component each time the gun fires. Consider using some type of delay to delete the component after the animation finishes.

How to properly test onScroll event value in React Native?

My code has a lot of animations that run off the same animationRange generated from the same FlatList onScroll. They all work as intended, but I need to add test coverage to where the animations are being invoked. Unfortunately, I am unaware of how to mock the animationRange.
I have tried mocking animationRange with something like this:
const mockInterpolation = jest.fn();
const mockAnimationRange = jest.fn().mockImplementation(() => {
return { interpolate: mockInterpolation }
});
but it's just returning an error when testing and I'm confident it's just because I don't know how to properly mock this value.
Here is the Flatlist that sets the animationRange
--------------------
<FlatList
onScroll={Animated.event([{
nativeEvent: { contentOffset: { y: animationRange } },
}],
{
useNativeDriver: true,
})}
/>
This animationRange value appears to be what I need to mock. And it needs to be able to handle the following:
export const AnimateScore = (animationRange) => {
return {
transform: [
{
translateX: animationRange.interpolate({
inputRange: [0, (100)],
outputRange: [0, screenWidth * 0.125)],
extrapolate: 'clamp',
}),
},
],
};
};
All I am looking for is the proper way to mock this value or test .interpolate for the onScroll's offset value.
Thank you in advance.