import React, { useEffect, useState } from 'react';import { StyleSheet, View } from 'react-native';import Animated, {withRepeat,useAnimatedStyle,useSharedValue,withTiming,useDerivedValue,} from 'react-native-reanimated';import { withPause } from 'react-native-redash';const SIZE = 100;export const AnimatedSquare = () => {const [isPlaying, setIsPlaying] = useState(false);const isPaused = useDerivedValue(() => !isPlaying, [isPlaying]);const progress = useSharedValue(0);const rStyle = useAnimatedStyle(() => ({borderRadius: progress.value * 20,transform: [{ scale: 0.5 + progress.value * 0.5 },{ rotate: `${progress.value * 360}deg` },],opacity: 0.5 + progress.value * 0.5,}));useEffect(() => {progress.value = withPause(withRepeat(withTiming(1, { duration: 2000 }), -1, true),isPaused);}, [isPaused]);return (<View style={styles.container}><Animated.View style={[styles.square, rStyle]} /><ButtononPress={() => setIsPlaying((prev) => !prev)}state={isPlaying ? 'active' : 'inactive'}/></View>);};const styles = StyleSheet.create({container: {flex: 1,alignItems: 'center',justifyContent: 'center',backgroundColor: '#1a1a1a',},square: {height: SIZE,width: SIZE,backgroundColor: 'rgba(255, 255, 255, 0.9)',},});
const InitialState = {borderRadius: 0,opacity: 0.5,transform: [{ rotate: '0deg' },{scale: 0.5,},],} as const;const FinalState = {borderRadius: 20,opacity: 1,transform: [{ rotate: '360deg' },{scale: 1,},],} as const;export const AnimatedSquare = () => {return (<View style={styles.container}><Animated.Viewstyle={[styles.square,{animationDuration: 2000,animationTimingFunction: 'easeInOut', // use the curve you'd like the mostanimationName: {from: InitialState,to: FinalState,},},]}/></View>);};
... // InitialState and FinalStateexport const AnimatedSquare = () => {return (<View style={styles.container}><Animated.Viewstyle={[styles.square,{animationDuration: 2000,animationTimingFunction: 'easeInOut',animationIterationCount: 'infinite', // repeat the animation infinitely (or just 1, 2, 3, etc...)animationDirection: 'alternate', // alternate the animation direction to create a boomerang effectanimationName: {from: InitialState,to: FinalState,},},]}/></View>);};
... // InitialState and FinalStateexport const AnimatedSquare = () => {const [isPlaying, setIsPlaying] = useState(false);return (<View style={styles.container}><Animated.Viewstyle={[styles.square,{animationDuration: 2000,animationTimingFunction: 'easeInOut',animationIterationCount: 'infinite',animationDirection: 'alternate',animationPlayState: isPlaying ? 'running' : 'paused',animationName: {from: InitialState,to: FinalState,},},]}/><ButtononPress={() => setIsPlaying((prev) => !prev)}state={isPlaying ? 'play' : 'pause'}/></View>);};
Every week I send out a newsletter sharing new things about React Native animations.