45 lines
1.1 KiB
TypeScript
45 lines
1.1 KiB
TypeScript
import { useEffect } from 'react';
|
|
import {
|
|
Easing,
|
|
cancelAnimation,
|
|
useAnimatedStyle,
|
|
useSharedValue,
|
|
withRepeat,
|
|
withTiming,
|
|
} from 'react-native-reanimated';
|
|
|
|
type AnimatedStyle = {
|
|
transform: Array<{ scale: number }>;
|
|
opacity: number;
|
|
};
|
|
|
|
export function usePulseAnimation(active: boolean, durationMs = 1600): AnimatedStyle {
|
|
const scale = useSharedValue(1);
|
|
const opacity = useSharedValue(active ? 1 : 0.5);
|
|
|
|
useEffect(() => {
|
|
if (active) {
|
|
scale.value = withRepeat(
|
|
withTiming(1.4, { duration: durationMs / 2, easing: Easing.out(Easing.quad) }),
|
|
-1,
|
|
true,
|
|
);
|
|
opacity.value = withRepeat(
|
|
withTiming(0.55, { duration: durationMs / 2, easing: Easing.inOut(Easing.quad) }),
|
|
-1,
|
|
true,
|
|
);
|
|
} else {
|
|
cancelAnimation(scale);
|
|
cancelAnimation(opacity);
|
|
scale.value = withTiming(1, { duration: 160 });
|
|
opacity.value = withTiming(0.5, { duration: 160 });
|
|
}
|
|
}, [active, durationMs, scale, opacity]);
|
|
|
|
return useAnimatedStyle<AnimatedStyle>(() => ({
|
|
transform: [{ scale: scale.value }],
|
|
opacity: opacity.value,
|
|
}));
|
|
}
|