I'm trying to animate a 50px circle to expand to 100px over 2 seconds, then stay at 100px for 2 seconds before starting to shrink down to 50px over 2 seconds. Then repeat this indefinitely.
Currently I've nailed the expanding part, but I can't figure out how to keep it at max width/height for 2 seconds and then shrink it down.
import React, { FunctionComponent, useEffect } from 'react';
import Animated, {
useAnimatedStyle,
useSharedValue,
withDelay,
withRepeat,
withSpring,
withTiming,
} from 'react-native-reanimated';
import styled from 'styled-components/native';
const CircleAnimation: FunctionComponent<Props> = () => {
const widthAndHeight = useSharedValue(50);
const duration = 2;
const foregroundCircleStyle = useAnimatedStyle(() => {
return {
width: widthAndHeight.value,
height: widthAndHeight.value,
borderRadius: widthAndHeight.value / 2,
};
});
useEffect(() => {
widthAndHeight.value = withDelay(
2000,
withRepeat(
withTiming(100, {
duration: duration * 1000,
}),
-1,
false
)
);
}, [duration, widthAndHeight]);
return <ForegroundCircle style={[foregroundCircleStyle]} />
};
const ForegroundCircle = styled(Animated.View)`
width: 50px;
height: 50px;
border-radius: 25px;
background-color: yellow;
`;
export default CircleAnimation;
I refactored your effect to something like this:
useEffect(() => {
widthAndHeight.value = withRepeat(
withSequence(
withTiming(255, { duration: breathLength * 1000 }),
withDelay(4000, withTiming(120, { duration: breathLength * 1000 }))
),
-1
);
}, [breathLength, widthAndHeight]);
And it seems to work like you described.
Explaining the code:
First, you want to repeat a certain animation forever, so you wrap the animation with the withRepeat
function, passing -1 as the second argument.
The animation you want to repeat is a sequence (withSequence
) of two animations:
withTiming
).withDelay
) and then shrink the circle back (withTiming
).Also, not related to animations, but if you want a perfect circle, your border-radius
should be at least width
(or height
, since they have the same value) divided by 2, so at least ~128px.