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.
Related
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?
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;
I'm totally new to animations in react-native and I'm trying to create an animated pulsating button using the react-native-reanimated library.
Animation concepts are really not that clear for me yet but by modifying someone else code, I got pretty close to what I want to create.
I would like to make this pulsating animation continuous. Currently, it pulsates and then stops. I'd appreciate some help with this. I'm including both the code and the snack for you to see a running sample. Please keep in mind that I simply modified someone else's code so I'm sure there are things in this code that are NOT necessary. I'm learning as I work on this button.
Here's a link to the snack: https://snack.expo.io/#imsam67/reanimated-test
And here's the code:
import React, { Component } from 'react';
import { StyleSheet, View } from 'react-native';
import Animated from 'react-native-reanimated';
const {
divide,
set,
cond,
startClock,
stopClock,
clockRunning,
block,
spring,
debug,
Value,
Clock,
} = Animated;
function runSpring(clock, value, dest) {
const state = {
finished: new Value(0),
velocity: new Value(0),
position: new Value(0),
time: new Value(0),
};
const config = {
toValue: new Value(0),
damping: 10,
mass: 5,
stiffness: 101.6,
overshootClamping: false,
restSpeedThreshold: 0.001,
restDisplacementThreshold: 0.001,
};
return block([
cond(clockRunning(clock), 0, [
set(state.finished, 0),
set(state.time, 0),
set(state.position, value),
set(state.velocity, -2500),
set(config.toValue, dest),
startClock(clock),
]),
spring(clock, state, config),
cond(state.finished, debug('stop clock', stopClock(clock))),
state.position,
]);
}
export default class Example extends Component {
constructor(props) {
super(props);
const clock = new Clock();
this._trans = runSpring(clock, 10, 150);
}
componentDidMount() {}
render() {
return (
<View style={styles.container}>
<Animated.View
style={[styles.circle, { borderWidth: divide(this._trans, 5) }]}>
</Animated.View>
</View>
);
}
}
const BOX_SIZE = 100;
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'black',
},
circle: {
backgroundColor: "white",
borderColor: "red",
borderRadius: 150,
height: 150,
width: 150
}
});
A quick way to get this animation to loop is to set the damping to 0. This will keep the spring animation going indefinitely.
const config = {
toValue: new Value(0),
damping: 0, // changed to 0
mass: 5
stiffness: 101.6,
overshootClamping: false,
restSpeedThreshold: 0.001,
restDisplacementThreshold: 0.001,
};
But you would want to change the borderWidth style to divide by a larger number to keep the border radius from overshooting.
<Animated.View
style={[styles.circle, { borderWidth: divide(this._trans, 25) }]}>
</Animated.View>
You can find the modified Snack here.
For a repeating animtion like this, you could also look at using Lottie, which is much simpler to implement, but less flexible.
Also, you could look at using loop from react native Animations which should allow you to set the border radius.
Another way to do it a bit more controlled with reanimated 1.x.x is:
const [clock] = useState(() => new Clock());
const loopingValue = useMemo(() => {
const state = {
finished: new Value(0),
position: new Value(0),
time: new Value(0),
frameTime: new Value(0),
};
const config = {
duration: new Value(2000),
toValue: new Value(1),
easing: Easing.linear,
};
const value = block([
// start right away
startClock(clock),
// process your state
timing(clock, state, config),
// when over (processed by timing at the end)
cond(state.finished, [
// we stop
stopClock(clock),
// set flag ready to be restarted
set(state.finished, 0),
// same value as the initial defined in the state creation
set(state.position, 0),
// very important to reset this ones !!! as mentioned in the doc about timing is saying
set(state.time, 0),
set(state.frameTime, 0),
// and we restart
startClock(clock),
]),
state.position,
]);
return interpolate(value, {
inputRange: [0, 0.5, 1],
outputRange: [0, 1, 0],
});
}, [clock]);
A lot of this code is copied from a github thread here: https://github.com/software-mansion/react-native-reanimated/issues/162
I want an animation to be executed when i open my keyboard and revert back when I close it.
The problem is:
undefined is not an object (evaluating 'this.state.scaleValue')
I have Keyboard.listener which works good.
State:
this.state = {
scaleValue: new Animated.Value(0),
}
Animated View
<Animated.View style={styles.logoContainer,
{
transform: [
{scale: logoScale}
]
}
}>
<Image source={require('./someimage.png')} style={{width: 64, height: 64}} />
</Animated.View>
Interpolate
const logoScale = this.state.scaleValue.interpolate({
inputRange: [0, 0.5, 1],
outputRange: [1, 0.5, 0]
});
Trigger
_keyboardDidShow () {
this.state.scaleValue.setValue(0);
Animated.timing(
this.state.ScaleValue,
{
toValue: 1,
duration: 300,
easing: Easing.easeOutBack
}
).start();
}
So, when I put the code from trigger into a function and call it onPress with Touchable, it works.
this does not have the same context inside the function supplied to Animated.timing.
You need to bind the method:
this._keyboardDidShow = this._keyboardDidShow.bind(this)
If that doesn't work you could probably even set let me = this above the call to timing (and refer to it as me within the body of the timing method call).
I'm trying to push a new screen onto a StackNavigator, but without animation. I need the effect to be instant. I'm looking through the docs, but I'm having a hard time discerning how to configure the transition for a StackNavigator. I only need do disable animation for one specific route.
In the StackNavigatorConfig section of this page I see some config objects outlined such as transitionConfig that seem potentially promising..? but how do I find a description of how to use these objects?
According to issue 1120, currently animation cannot be disabled.
And transitionConfig is not well documented, its definition can be found here
export type NavigationTransitionSpec = {
duration?: number,
// An easing function from `Easing`.
easing?: (t: number) => number,
// A timing function such as `Animated.timing`.
timing?: (value: AnimatedValue, config: any) => any,
};
/**
* Describes a visual transition from one screen to another.
*/
export type TransitionConfig = {
// The basics properties of the animation, such as duration and easing
transitionSpec?: NavigationTransitionSpec,
// How to animate position and opacity of the screen
// based on the value generated by the transitionSpec
screenInterpolator?: (props: NavigationSceneRendererProps) => Object,
};
Example FYI:
// custom Modal transition animation
transitionConfig: () => ({
transitionSpec: {
duration: 250,
easing: Easing.out(Easing.poly(4)),
timing: Animated.timing,
},
screenInterpolator: sceneProps => {
const { layout, position, scene } = sceneProps
const { index } = scene
const height = layout.initHeight
const translateY = position.interpolate({
inputRange: [index - 1, index, index + 1],
outputRange: [height, 0, 0],
})
const opacity = position.interpolate({
inputRange: [index - 1, index - 0.99, index],
outputRange: [0, 1, 1],
})
return { opacity, transform: [{ translateY }] }
},
}),