-
|
I've made custom entering animation i.e. const enterAnimation: EntryExitAnimationFunction = () => {
'worklet'
const animations = {
opacity: withTiming(1, AnimationTool.introTiming),
transform: [
{ scale: withSpring(1, AnimationTool.introSpring) },
{ translateY: withSpring(0, AnimationTool.introSpring) },
{ rotate: withSpring('0deg', AnimationTool.introSpring) }
]
}
const initialValues = {
opacity: 0,
transform: [{ scale: 0.6 }, { translateY: 40 }, { rotate: '-5deg' }]
}
return { animations, initialValues }
}And am using it on my views via <>
<Animated.View entering={enterAnimation} />
<Animated.View entering={enterAnimation} />
<Animated.View entering={enterAnimation} />
<Animated.View entering={enterAnimation} />
<Animated.View entering={enterAnimation} />
</>This is working great, but I need to animate / enter each view with a different delay based on their index. I can easily add here is example with delays added, I'm trying to figure out how to make that const enterAnimation: EntryExitAnimationFunction = () => {
'worklet'
const animations = {
opacity: withDelay(1000, withTiming(1, AnimationTool.introTiming)),
transform: [
{ scale: withDelay(1000, withSpring(1, AnimationTool.introSpring)) },
{ translateY: withDelay(1000, withSpring(0, AnimationTool.introSpring)) },
{ rotate: withDelay(1000, withSpring('0deg', AnimationTool.introSpring)) }
]
}
const initialValues = {
opacity: 0,
transform: [{ scale: 0.6 }, { translateY: 40 }, { rotate: '-5deg' }]
}
return { animations, initialValues }
} |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 1 reply
-
|
This is what I do, create a wrapper View that accept the delay Then in you can just use it like so |
Beta Was this translation helpful? Give feedback.
-
|
Hey! Solution 1You can use the API that we use internally to create layout animations in the following way: class MyLayoutAnimation
extends ComplexAnimationBuilder
implements IEntryExitAnimationBuilder
{
static presetName = 'MyLayoutAnimation';
static createInstance<T extends typeof BaseAnimationBuilder>(
this: T
): InstanceType<T> {
return new MyLayoutAnimation() as InstanceType<T>;
}
build = (): EntryExitAnimationFunction => {
const delayFunction = this.getDelayFunction();
const callback = this.callbackV;
const initialValues = this.initialValues;
const delay = this.getDelay();
return () => {
'worklet';
return {
animations: {
opacity: delayFunction(
delay,
withTiming(1, AnimationTool.introTiming)
),
transform: [
{
scale: delayFunction(
delay,
withSpring(1, AnimationTool.introSpring)
),
},
{
translateY: delayFunction(
delay,
withSpring(0, AnimationTool.introSpring)
),
},
{
rotate: delayFunction(
delay,
withSpring('0deg', AnimationTool.introSpring)
),
},
],
},
initialValues: {
opacity: 0,
transform: [{ scale: 0.6 }, { translateY: 40 }, { rotate: '-5deg' }],
...initialValues,
},
callback,
};
};
};
}This will allow you to specify a custom delay, similarly as you can do with built-in layout animations: <>
<Animated.View style={styles.box} entering={MyLayoutAnimation} />
<Animated.View style={styles.box} entering={MyLayoutAnimation.delay(1000)} />
<Animated.View style={styles.box} entering={MyLayoutAnimation.delay(1500)} />
<Animated.View style={styles.box} entering={MyLayoutAnimation.delay(2000)} />
</>Solution 2Alternatively, you can just wrap your layout animation function with a another function that accepts the delay parameter: const MyLayoutAnimation =
(delay = 0): EntryExitAnimationFunction =>
() => {
'worklet';
const animations = {
opacity: withDelay(delay, withTiming(1, AnimationTool.introTiming)),
transform: [
{ scale: withDelay(delay, withSpring(1, AnimationTool.introSpring)) },
{
translateY: withDelay(
delay,
withSpring(0, AnimationTool.introSpring)
),
},
{
rotate: withDelay(
delay,
withSpring('0deg', AnimationTool.introSpring)
),
},
],
};
const initialValues = {
opacity: 0,
transform: [{ scale: 0.6 }, { translateY: 40 }, { rotate: '-5deg' }],
};
return { animations, initialValues };
};and use it as follows: <>
<Animated.View style={styles.box} entering={MyLayoutAnimation()} />
<Animated.View style={styles.box} entering={MyLayoutAnimation(500)} />
<Animated.View style={styles.box} entering={MyLayoutAnimation(1000)} />
<Animated.View style={styles.box} entering={MyLayoutAnimation(1500)} />
</> |
Beta Was this translation helpful? Give feedback.
-
|
Staggered entering animations based on component index are a great pattern for list items, cards, and grid layouts. A few approaches: Approach 1: delay based on index prop function AnimatedCard({ index }: { index: number }) {
const entering = FadeInDown.delay(index * 80).springify();
return (
<Animated.View entering={entering}>
{/* content */}
</Animated.View>
);
}Simple and works for static lists. Limitation: if the list re-renders, items that are already visible re-animate. Approach 2: shared value with delay function AnimatedCard({ index }: { index: number }) {
const sv = useSharedValue(0);
useEffect(() => {
sv.value = withDelay(
index * 80,
withSpring(1, { damping: 15 })
);
}, []);
const style = useAnimatedStyle(() => ({
opacity: sv.value,
transform: [{ translateY: interpolate(sv.value, [0, 1], [20, 0]) }],
}));
return <Animated.View style={style}>{/* content */}</Animated.View>;
}More control — can be triggered by conditions other than mount. Approach 3: parent-driven via Layout Animations Performance note: if you have many items (50+), staggered animations can create janky rendering as all items try to animate simultaneously with overlapping delays. For long lists, limit the stagger to the first N visible items and skip animation for items below the fold. Is the goal entrance animation (items appear one by one) or a different interaction (like drag reorder)? |
Beta Was this translation helpful? Give feedback.
Hey!
I know that this discussion is quite old but maybe this comment will help someone.
Solution 1
You can use the API that we use internally to create layout animations in the following way: