npx expo install react-native-reanimated react-native-gesture-handler
import { Dimensions, StyleSheet, View } from 'react-native';import { GestureHandlerRootView } from 'react-native-gesture-handler';const { width: SCREEN_WIDTH } = Dimensions.get('window');const SIZE = 80;export default function App() {return (<GestureHandlerRootView style={{ flex: 1 }}><View style={styles.container}><View style={styles.circle} /></View></GestureHandlerRootView>);}const styles = StyleSheet.create({container: {flex: 1,backgroundColor: '#fff',},circle: {position: 'absolute',height: SIZE,aspectRatio: 1,backgroundColor: 'blue',borderRadius: SIZE / 2,opacity: 0.8,},});
...import {GestureDetector,GestureHandlerRootView,} from 'react-native-gesture-handler';...export default function App() {return (<GestureHandlerRootView style={{ flex: 1 }}><View style={styles.container}><GestureDetector gesture={🧐}><Animated.View style={styles.circle} /></GestureDetector></View></GestureHandlerRootView>);}...
...import {Gesture,GestureDetector,GestureHandlerRootView,} from 'react-native-gesture-handler';...export default function App() {const gesture = Gesture.Pan().onUpdate((event) => {console.log(event.translationX)})return (<GestureHandlerRootView style={{ flex: 1 }}><View style={styles.container}><GestureDetector gesture={gesture}><Animated.View style={styles.circle} /></GestureDetector></View></GestureHandlerRootView>);}...
const translateX = useSharedValue(0);const gesture = Gesture.Pan().onUpdate(event => {translateX.value = event.translationX;});
const rStyle = useAnimatedStyle(() => {return {transform: [{ translateX: translateX.value }],};});
const translateX = useSharedValue(0);const translateY = useSharedValue(0);const gesture = Gesture.Pan().onUpdate(event => {translateX.value = event.translationX;translateY.value = event.translationY;});const rStyle = useAnimatedStyle(() => {return {transform: [{ translateX: translateX.value },{ translateY: translateY.value },],};});
const translateX = useSharedValue(0);const translateY = useSharedValue(0);const context = useSharedValue({ x: 0, y: 0 });const gesture = Gesture.Pan().onStart(() => {context.value = { x: translateX.value, y: translateY.value };}).onUpdate(event => {translateX.value = event.translationX + context.value.x;translateY.value = event.translationY + context.value.y;});const rStyle = useAnimatedStyle(() => {return {transform: [{ translateX: translateX.value },{ translateY: translateY.value },],};});
...const translateX = useSharedValue(0)const translateY = useSharedValue(0)const context = useSharedValue({ x: 0, y: 0 })const gesture = Gesture.Pan().onStart(() => {context.value = { x: translateX.value, y: translateY.value }}).onUpdate((event) => {translateX.value = event.translationX + context.value.xtranslateY.value = event.translationY + context.value.y})const followX = useDerivedValue(() => {return withSpring(translateX.value)})const followY = useDerivedValue(() => {return withSpring(translateY.value)})...
...const rStyle = useAnimatedStyle(() => {return {transform: [{ translateX: followX.value }, { translateY: followY.value }],}})
...interface AnimatedPosition {x: Animated.SharedValue<number>y: Animated.SharedValue<number>}const useFollowAnimatedPosition = ({ x, y }: AnimatedPosition) => {const followX = useDerivedValue(() => {return withSpring(x.value)})const followY = useDerivedValue(() => {return withSpring(y.value)})const rStyle = useAnimatedStyle(() => {return {transform: [{ translateX: followX.value }, { translateY: followY.value }],}})return { followX, followY, rStyle }}...
...export default function App() {const translateX = useSharedValue(0);const translateY = useSharedValue(0);const context = useSharedValue({ x: 0, y: 0 });const gesture = Gesture.Pan().onStart(() => {context.value = { x: translateX.value, y: translateY.value };}).onUpdate((event) => {translateX.value = event.translationX + context.value.x;translateY.value = event.translationY + context.value.y;})const {followX: blueFollowX,followY: blueFollowY,rStyle: rBlueCircleStyle,} = useFollowAnimatedPosition({x: translateX,y: translateY,});return (<GestureHandlerRootView style={{ flex: 1 }}><View style={styles.container}><GestureDetector gesture={gesture}><Animated.View style={[styles.circle, rBlueCircleStyle]} /></GestureDetector></View></GestureHandlerRootView>);}...
const {followX: blueFollowX,followY: blueFollowY,rStyle: rBlueCircleStyle,} = useFollowAnimatedPosition({x: translateX,y: translateY,});const {followX: redFollowX,followY: redFollowY,rStyle: rRedCircleStyle,} = useFollowAnimatedPosition({x: blueFollowX,y: blueFollowY,});return (<GestureHandlerRootView style={{ flex: 1 }}><View style={styles.container}><Animated.Viewstyle={[styles.circle, { backgroundColor: 'red' }, rRedCircleStyle]}/><GestureDetector gesture={gesture}><Animated.View style={[styles.circle, rBlueCircleStyle]} /></GestureDetector></View></GestureHandlerRootView>);
const {followX: blueFollowX,followY: blueFollowY,rStyle: rBlueCircleStyle,} = useFollowAnimatedPosition({x: translateX,y: translateY,});const {followX: redFollowX,followY: redFollowY,rStyle: rRedCircleStyle,} = useFollowAnimatedPosition({x: blueFollowX,y: blueFollowY,});const { rStyle: rGreenCircleStyle } = useFollowAnimatedPosition({x: redFollowX,y: redFollowY,});return (<GestureHandlerRootView style={{ flex: 1 }}><View style={styles.container}><Animated.Viewstyle={[styles.circle, { backgroundColor: 'green' }, rGreenCircleStyle]}/><Animated.Viewstyle={[styles.circle, { backgroundColor: 'red' }, rRedCircleStyle]}/><GestureDetector gesture={gesture}><Animated.View style={[styles.circle, rBlueCircleStyle]} /></GestureDetector></View></GestureHandlerRootView>);
const gesture = Gesture.Pan().onStart(() => {context.value = { x: translateX.value, y: translateY.value };}).onUpdate(event => {translateX.value = event.translationX + context.value.x;translateY.value = event.translationY + context.value.y;}).onEnd(() => {if (translateX.value > SCREEN_WIDTH / 2) {translateX.value = SCREEN_WIDTH;} else {translateX.value = 0;}});
const gesture = Gesture.Pan().onStart(() => {context.value = { x: translateX.value, y: translateY.value };}).onUpdate(event => {translateX.value = event.translationX + context.value.x;translateY.value = event.translationY + context.value.y;}).onEnd(() => {if (translateX.value > SCREEN_WIDTH / 2) {translateX.value = SCREEN_WIDTH - SIZE;} else {translateX.value = 0;}});
import { Dimensions, StyleSheet, View } from 'react-native';import {Gesture,GestureDetector,GestureHandlerRootView,} from 'react-native-gesture-handler';import Animated, {useAnimatedGestureHandler,useAnimatedStyle,useDerivedValue,useSharedValue,withSpring,} from 'react-native-reanimated';interface AnimatedPosition {x: Animated.SharedValue<number>;y: Animated.SharedValue<number>;}const useFollowAnimatedPosition = ({ x, y }: AnimatedPosition) => {const followX = useDerivedValue(() => {return withSpring(x.value);});const followY = useDerivedValue(() => {return withSpring(y.value);});const rStyle = useAnimatedStyle(() => {return {transform: [{ translateX: followX.value }, { translateY: followY.value }],};});return { followX, followY, rStyle };};const { width: SCREEN_WIDTH } = Dimensions.get('window');const SIZE = 80;export default function App() {const translateX = useSharedValue(0);const translateY = useSharedValue(0);const context = useSharedValue({ x: 0, y: 0 });const gesture = Gesture.Pan().onStart(() => {context.value = { x: translateX.value, y: translateY.value };}).onUpdate(event => {translateX.value = event.translationX + context.value.x;translateY.value = event.translationY + context.value.y;}).onEnd(() => {if (translateX.value > SCREEN_WIDTH / 2) {translateX.value = SCREEN_WIDTH - SIZE;} else {translateX.value = 0;}});const {followX: blueFollowX,followY: blueFollowY,rStyle: rBlueCircleStyle,} = useFollowAnimatedPosition({x: translateX,y: translateY,});const {followX: redFollowX,followY: redFollowY,rStyle: rRedCircleStyle,} = useFollowAnimatedPosition({x: blueFollowX,y: blueFollowY,});const { rStyle: rGreenCircleStyle } = useFollowAnimatedPosition({x: redFollowX,y: redFollowY,});return (<GestureHandlerRootView style={{ flex: 1 }}><View style={styles.container}><Animated.Viewstyle={[styles.circle,{ backgroundColor: 'green' },rGreenCircleStyle,]}/><Animated.Viewstyle={[styles.circle, { backgroundColor: 'red' }, rRedCircleStyle]}/><GestureDetector gesture={gesture}><Animated.View style={[styles.circle, rBlueCircleStyle]} /></GestureDetector></View></GestureHandlerRootView>);}const styles = StyleSheet.create({container: {flex: 1,backgroundColor: '#fff',},circle: {position: 'absolute',height: SIZE,aspectRatio: 1,backgroundColor: 'blue',borderRadius: SIZE / 2,opacity: 0.8,},});
Every week I send out a newsletter sharing new things about React Native animations.