React Native Reanimated 4: Kompletný sprievodca animáciami a gestami v Expo

Naučte sa vytvárať plynulé 120+ FPS animácie v React Native s Reanimated 4 a Expo. Sprievodca pokrýva CSS prechody, worklets, Gesture Handler integráciu a praktické príklady vrátane drag-and-drop kariet a bottom sheetu.

Úvod: Prečo sú animácie kľúčové pre mobilné aplikácie

Povedzme si to na rovinu — plynulé animácie a intuitívne gestá nie sú len pekný vizuálny bonus. Sú úplne zásadné pre to, ako používateľ vníma vašu aplikáciu. Podľa prieskumu State of React Native 2025 používa knižnicu React Native Reanimated až 93 % vývojárov. A úprimne, keď vyskúšate Reanimated 4, pochopíte prečo.

S príchodom verzie 4 v roku 2026 sa animovanie v React Native dramaticky zjednodušilo. CSS-like animácie a prechody priamo v natívnom prostredí? Áno, konečne.

V tomto sprievodcovi si prejdeme všetko od základov po pokročilé techniky — inštaláciu v Expo, zdieľané hodnoty, animované štýly, CSS prechody, integráciu s Gesture Handler a praktické príklady, ktoré môžete rovno skopírovať do svojich projektov. Tak poďme na to.

Čo je React Native Reanimated 4 a prečo ho potrebujete

React Native Reanimated je výkonná animačná knižnica, ktorá presúva výpočty animácií z JavaScript vlákna priamo na UI vlákno. Čo to znamená v praxi? Vaše animácie zostanú plynulé aj vtedy, keď JavaScript rieši nejaký ťažký výpočet alebo sieťovú požiadavku. Žiadne sekanie, žiadne zasekávanie.

Reanimated 4 vs. vstavaný Animated API

Vstavaný Animated API v React Native vyžaduje explicitné nastavenie useNativeDriver: true pre animácie na UI vlákne a podporuje len obmedzený počet vlastností. Reanimated 4 tieto obmedzenia jednoducho odstraňuje:

  • Všetko beží na UI vlákne — žiadne nastavovanie, animácie bežia natívne automaticky
  • Až 120+ FPS — plynulé animácie aj na zariadeniach s vyššou obnovovacou frekvenciou
  • CSS-like animácie — nové v Reanimated 4, deklaratívny prístup známy z webu
  • Žiadne zbytočné re-rendery — hodnoty žijú mimo React stavu
  • Natívna integrácia s gestami — spolupráca s Gesture Handler funguje bezproblémovo
  • Optimalizovaný pre Novú architektúru — Fabric a konkurentné renderovanie

Požiadavky pre Reanimated 4

Reanimated 4 vyžaduje Novú architektúru React Native (Fabric). Ak používate Expo SDK 55, máte ju zapnutú automaticky — žiadna extra konfigurácia. Pre staršie projekty na starej architektúre zostáva dostupná verzia 3.x, ale tá už nie je aktívne udržiavaná (takže migrácia skôr či neskôr príde).

Inštalácia a konfigurácia v Expo

Nastavenie Reanimated 4 v Expo projekte je príjemne jednoduché. Dva kroky a ste hotoví.

Krok 1: Inštalácia balíkov

Reanimated 4 oddelil worklets do samostatného balíka react-native-worklets pre lepšiu modularitu. Nainštalujte oba:

npx expo install react-native-reanimated react-native-worklets

Krok 2: Overenie konfigurácie

V Expo projekte nie je potrebná žiadna ďalšia konfigurácia — Reanimated Babel plugin je automaticky nakonfigurovaný v babel-preset-expo. Ak však používate vlastnú konfiguráciu, uistite sa, že váš babel.config.js obsahuje plugin na poslednom mieste:

// babel.config.js
module.exports = function (api) {
  api.cache(true);
  return {
    presets: ['babel-preset-expo'],
    plugins: [
      // ... ostatné pluginy
      'react-native-worklets/plugin', // MUSÍ byť posledný
    ],
  };
};

Po inštalácii vyčistite cache a reštartujte Metro bundler:

npx expo start --clear

Základné koncepty: Zdieľané hodnoty a animované štýly

Pred vytvorením prvej animácie si potrebujete osvojiť dva základné stavebné bloky. Nebojte sa, nie je to nič zložité.

Zdieľané hodnoty (Shared Values)

Zdieľaná hodnota je centrálny mechanizmus pre uchovávanie animačných dát. Predstavte si ju ako React stav, ktorý je automaticky synchronizovaný medzi JavaScriptom a natívnou stranou aplikácie. Vytvárate ich cez hook useSharedValue:

import { useSharedValue } from 'react-native-reanimated';

function MyComponent() {
  const offset = useSharedValue(0);
  const opacity = useSharedValue(1);
  const scale = useSharedValue(1);

  // Aktualizácia hodnoty — vždy cez .value
  const handlePress = () => {
    offset.value = 100;    // Správne
    // offset = 100;       // NESPRÁVNE — bežná chyba
  };

  return null;
}

Dôležité: Klasická chyba začiatočníkov — nikdy nemodifikujte zdieľanú hodnotu priamo ako sv = 100. Vždy pristupujte cez .value: sv.value = 100. Sám som sa na tom chytil viackrát, kým si to mozog zapamätal.

Animované štýly (useAnimatedStyle)

Hook useAnimatedStyle vytvára animované štýly, ktoré reagujú na zmeny zdieľaných hodnôt bez vyvolania re-renderu komponentu. To je to kúzlo — UI sa mení, ale React o tom vlastne „nevie":

import Animated, {
  useSharedValue,
  useAnimatedStyle,
  withSpring,
} from 'react-native-reanimated';
import { Pressable, View, StyleSheet } from 'react-native';

function AnimatedBox() {
  const offset = useSharedValue(0);

  const animatedStyles = useAnimatedStyle(() => ({
    transform: [{ translateX: offset.value }],
  }));

  const handlePress = () => {
    offset.value = withSpring(offset.value === 0 ? 200 : 0);
  };

  return (
    
      
        
      
    
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, alignItems: 'center', justifyContent: 'center' },
  box: { width: 100, height: 100, backgroundColor: '#6C63FF', borderRadius: 16 },
});

Tri základné animačné funkcie

Reanimated ponúka tri vstavané animačné pomocníky, ktoré pokryjú väčšinu toho, čo budete potrebovať:

  • withTiming(toValue, config) — lineárna alebo easingová animácia s definovanou dĺžkou trvania
  • withSpring(toValue, config) — fyzikálna pružinová animácia pre prirodzený pohyb (osobne moja najobľúbenejšia)
  • withDecay(config) — spomaľujúca animácia založená na počiatočnej rýchlosti, ideálna pre gestá
import { withTiming, withSpring, withDecay, Easing } from 'react-native-reanimated';

// Timing animácia — 500ms s ease-in-out
offset.value = withTiming(200, {
  duration: 500,
  easing: Easing.bezier(0.25, 0.1, 0.25, 1),
});

// Spring animácia — fyzikálne realistický odraz
scale.value = withSpring(1.5, {
  damping: 10,
  stiffness: 100,
  mass: 1,
});

// Decay animácia — postupné spomalenie
offset.value = withDecay({
  velocity: velocityFromGesture,
  deceleration: 0.998,
});

CSS animácie a prechody — novinka v Reanimated 4

Toto je podľa mňa najväčšia vec, čo Reanimated 4 priniesol — podpora CSS-like animácií a prechodov. Ak ste niekedy písali CSS na webe, budete sa cítiť ako doma. Namiesto manuálneho riadenia animačných hodnôt jednoducho deklarujete, čo sa má animovať a ako. Reanimated sa postará o zvyšok.

CSS prechody (Transitions)

CSS prechody sú ideálne pre animácie vyvolané zmenou stavu. Stačí definovať vlastnosti prechodu priamo v štýloch Animated.View:

import React, { useState } from 'react';
import { Pressable, View, StyleSheet } from 'react-native';
import Animated from 'react-native-reanimated';

function CSSTransitionExample() {
  const [isExpanded, setIsExpanded] = useState(false);

  return (
    
       setIsExpanded(!isExpanded)}>
        
      
    
  );
}

Všimnite si — žiadne zdieľané hodnoty, žiadny useAnimatedStyle. Len React stav a deklarácia prechodu. Množstvo kódu, ktoré tým ušetríte, je naozaj citeľné.

CSS keyframe animácie

Pre opakujúce sa alebo viacfázové animácie môžete definovať keyframes úplne rovnako ako v CSS:

import React from 'react';
import { View, StyleSheet } from 'react-native';
import Animated from 'react-native-reanimated';

const pulseKeyframes = {
  from: { transform: [{ scale: 1 }], opacity: 1 },
  '50%': { transform: [{ scale: 1.15 }], opacity: 0.8 },
  to: { transform: [{ scale: 1 }], opacity: 1 },
};

const shimmerKeyframes = {
  from: { opacity: 0.4 },
  '50%': { opacity: 1 },
  to: { opacity: 0.4 },
};

function PulsingNotification() {
  return (
    
      
    
  );
}

function LoadingSkeleton() {
  return (
    
  );
}

Kedy použiť CSS prechody a kedy worklets

Reanimated 4 vám dáva dva výkonné prístupy. Tu je rýchle pravidlo:

  • CSS prechody — pre jednoduché stavové zmeny (toggle, expand/collapse, zmena farby), hover efekty, loading stavy. Menej kódu, jednoduchšia údržba.
  • Worklets — pre gestami riadené animácie, scroll efekty, drag-and-drop, čokoľvek kde potrebujete frame-by-frame kontrolu. Výkonnejšie, ale aj trochu zložitejšie.

Moja rada? Začnite s CSS prechodmi. Siahajte po worklets až keď narazíte na niečo, čo CSS prechody jednoducho nevedia.

Integrácia s React Native Gesture Handler

Tu sa Reanimated začína poriadne leskať. Kombinácia s React Native Gesture Handler umožňuje vytvárať plynulé, gestami ovládané animácie bežiace výlučne na UI vlákne. Výsledok? Dotykové interakcie, ktoré sa cítia naozaj natívne.

Inštalácia Gesture Handler

npx expo install react-native-gesture-handler

Konfigurácia GestureHandlerRootView

Celú aplikáciu musíte obaliť komponentom GestureHandlerRootView. Bez neho gestá jednoducho nebudú fungovať (a budete sa čudovať, prečo — verím mi, stalo sa mi to):

import { GestureHandlerRootView } from 'react-native-gesture-handler';

export default function App() {
  return (
    
      {/* Zvyšok aplikácie */}
    
  );
}

Príklad: Drag-and-drop karta s pružinovým efektom

Toto je jeden z mojich obľúbených príkladov — posúvateľná karta, ktorá sa po pustení vráti pružinovým efektom na pôvodnú pozíciu:

import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import Animated, {
  useSharedValue,
  useAnimatedStyle,
  withSpring,
} from 'react-native-reanimated';
import { Gesture, GestureDetector } from 'react-native-gesture-handler';

function DraggableCard() {
  const translateX = useSharedValue(0);
  const translateY = useSharedValue(0);
  const scale = useSharedValue(1);

  const panGesture = Gesture.Pan()
    .onStart(() => {
      scale.value = withSpring(1.05);
    })
    .onUpdate((event) => {
      translateX.value = event.translationX;
      translateY.value = event.translationY;
    })
    .onEnd(() => {
      translateX.value = withSpring(0);
      translateY.value = withSpring(0);
      scale.value = withSpring(1);
    });

  const animatedStyle = useAnimatedStyle(() => ({
    transform: [
      { translateX: translateX.value },
      { translateY: translateY.value },
      { scale: scale.value },
    ],
  }));

  return (
    
      
        
          Presuň ma
          Karta sa vráti na miesto
        
      
    
  );
}

const styles = StyleSheet.create({
  container: { flex: 1, alignItems: 'center', justifyContent: 'center' },
  card: {
    width: 280,
    padding: 24,
    backgroundColor: '#FFFFFF',
    borderRadius: 20,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 8 },
    shadowOpacity: 0.15,
    shadowRadius: 24,
    elevation: 8,
  },
  cardTitle: { fontSize: 18, fontWeight: '700', color: '#1F2937' },
  cardSubtitle: { fontSize: 14, color: '#6B7280', marginTop: 4 },
});

Príklad: Double-tap na zväčšenie obrázka

Ďalší praktický vzor — dvojité ťuknutie na priblíženie, kombinované s pinch gestom:

import React from 'react';
import { View, StyleSheet } from 'react-native';
import Animated, {
  useSharedValue,
  useAnimatedStyle,
  withSpring,
} from 'react-native-reanimated';
import { Gesture, GestureDetector } from 'react-native-gesture-handler';

function ZoomableImage({ source }) {
  const scale = useSharedValue(1);
  const savedScale = useSharedValue(1);

  const doubleTap = Gesture.Tap()
    .numberOfTaps(2)
    .onEnd(() => {
      if (scale.value > 1) {
        scale.value = withSpring(1);
        savedScale.value = 1;
      } else {
        scale.value = withSpring(2);
        savedScale.value = 2;
      }
    });

  const pinchGesture = Gesture.Pinch()
    .onUpdate((event) => {
      scale.value = savedScale.value * event.scale;
    })
    .onEnd(() => {
      if (scale.value < 1) {
        scale.value = withSpring(1);
        savedScale.value = 1;
      } else {
        savedScale.value = scale.value;
      }
    });

  const composed = Gesture.Simultaneous(doubleTap, pinchGesture);

  const animatedStyle = useAnimatedStyle(() => ({
    transform: [{ scale: scale.value }],
  }));

  return (
    
      
    
  );
}

const styles = StyleSheet.create({
  image: { width: 300, height: 300, borderRadius: 16 },
});

Layout animácie: Vstup, odchod a zmeny rozloženia

Reanimated ponúka predpripravené layout animácie pre komponenty, ktoré sa objavujú, miznú alebo menia pozíciu. Aktivujete ich jednoducho pridaním vlastností entering a exiting — a je to:

import Animated, {
  FadeIn,
  FadeOut,
  SlideInRight,
  SlideOutLeft,
  BounceIn,
  Layout,
} from 'react-native-reanimated';

function AnimatedList({ items }) {
  return (
    
      {items.map((item) => (
        
          {item.title}
        
      ))}
    
  );
}

// Príklad s toast notifikáciou
function NotificationToast({ visible, message }) {
  if (!visible) return null;

  return (
    
      {message}
    
  );
}

K dispozícii máte FadeIn/FadeOut, SlideInLeft/SlideOutRight, BounceIn/BounceOut, FlipInX/FlipOutY, ZoomIn/ZoomOut a ďalšie. Každú môžete konfigurovať reťazením metód, čo je veľmi pohodlné.

Praktický projekt: Animovaný bottom sheet

Dobre, teraz to celé spojíme dokopy. Nasledujúci príklad je animovaný bottom sheet ovládaný gestami — niečo, čo pravdepodobne budete potrebovať v každej druhej aplikácii:

import React from 'react';
import { View, Text, StyleSheet, Dimensions } from 'react-native';
import Animated, {
  useSharedValue,
  useAnimatedStyle,
  withSpring,
  interpolate,
  Extrapolation,
} from 'react-native-reanimated';
import { Gesture, GestureDetector } from 'react-native-gesture-handler';

const { height: SCREEN_HEIGHT } = Dimensions.get('window');
const MAX_TRANSLATE_Y = -SCREEN_HEIGHT + 80;
const MIN_TRANSLATE_Y = -120;

function BottomSheet({ children }) {
  const translateY = useSharedValue(MIN_TRANSLATE_Y);
  const context = useSharedValue({ y: 0 });

  const panGesture = Gesture.Pan()
    .onStart(() => {
      context.value = { y: translateY.value };
    })
    .onUpdate((event) => {
      translateY.value = Math.max(
        MAX_TRANSLATE_Y,
        Math.min(MIN_TRANSLATE_Y, context.value.y + event.translationY)
      );
    })
    .onEnd((event) => {
      // Prichytiť na otvorenú alebo zatvorenú pozíciu
      if (translateY.value > -SCREEN_HEIGHT / 3) {
        translateY.value = withSpring(MIN_TRANSLATE_Y, { damping: 20 });
      } else {
        translateY.value = withSpring(MAX_TRANSLATE_Y, { damping: 20 });
      }
    });

  const sheetStyle = useAnimatedStyle(() => ({
    transform: [{ translateY: translateY.value }],
  }));

  const backdropStyle = useAnimatedStyle(() => ({
    opacity: interpolate(
      translateY.value,
      [MIN_TRANSLATE_Y, MAX_TRANSLATE_Y],
      [0, 0.5],
      Extrapolation.CLAMP
    ),
  }));

  return (
    <>
      
      
        
          
          {children}
        
      
    
  );
}

const styles = StyleSheet.create({
  backdrop: {
    ...StyleSheet.absoluteFillObject,
    backgroundColor: '#000',
  },
  sheet: {
    height: SCREEN_HEIGHT,
    width: '100%',
    backgroundColor: '#FFFFFF',
    position: 'absolute',
    top: SCREEN_HEIGHT,
    borderTopLeftRadius: 24,
    borderTopRightRadius: 24,
    paddingHorizontal: 20,
  },
  handle: {
    width: 40,
    height: 4,
    backgroundColor: '#D1D5DB',
    borderRadius: 2,
    alignSelf: 'center',
    marginVertical: 12,
  },
});

Tento bottom sheet kombinuje Pan gesto pre ťahanie, pružinovú animáciu pre prichytenie, interpoláciu pre priehľadnosť pozadia a zdieľané hodnoty pre plynulý pohyb. A to všetko beží na UI vlákne bez zaťaženia JavaScriptu. Celkom elegantné, nie?

Tipy na optimalizáciu výkonu animácií

Reanimated je síce navrhnutý pre vysoký výkon, ale aj tak existuje pár vecí, na ktoré sa oplatí dávať pozor:

  • Preferujte non-layout vlastnosti — animovanie transform, opacity a backgroundColor je výrazne rýchlejšie ako animovanie width, height alebo margin, pretože tie vyžadujú prepočet rozloženia na každom snímku.
  • Aktualizujte na Reanimated 4.2.0+ — novšie verzie prinášajú optimalizácie pre scény s mnohými animovanými komponentmi.
  • Používajte cancelAnimation — vždy zastavte prebiehajúce animácie pred spustením nových na rovnakej zdieľanej hodnote. Inak sa vám môžu animácie „biť".
  • Minimalizujte runOnJS — volanie JavaScript funkcií z UI vlákna pridáva latenciu. Používajte len keď naozaj musíte.
  • Oddeľte animované a neanimované komponenty — komponent obalený v Animated by mal obsahovať len to, čo sa skutočne animuje.

Riešenie bežných problémov

Animácie sa nespúšťajú

Najčastejšia príčina? Chýbajúci alebo nesprávne nakonfigurovaný Babel plugin. Overte, že react-native-worklets/plugin je prítomný vo vašom babel.config.js a je posledný v zozname pluginov. Po úprave nezabudnite vyčistiť cache: npx expo start --clear.

Chyba GestureHandlerRootView

Ak vidíte chybu "GestureDetector must be used as a descendant of GestureHandlerRootView", znamená to, že vaša aplikácia nie je obalená GestureHandlerRootView. V Expo Router ho pridajte do koreňového layoutu app/_layout.tsx.

Pokles FPS pri mnohých animovaných komponentoch

Pri scénach s veľkým počtom súčasne animovaných komponentov pomôže aktualizácia na React Native 0.80+ a Reanimated 4.2.0+. Aktivujte tiež feature flag USE_COMMIT_HOOK_ONLY_FOR_REACT_COMMITS — v praxi to robí merateľný rozdiel.

Často kladené otázky (FAQ)

Je Reanimated 4 kompatibilný s Expo SDK 55?

Áno, plne. Expo SDK 55 má automaticky zapnutú Novú architektúru (Fabric), čo je hlavná požiadavka Reanimated 4. Stačí npx expo install a Babel plugin sa nakonfiguruje sám.

Aký je rozdiel medzi CSS prechodmi a worklets v Reanimated 4?

CSS prechody sú deklaratívne — definujete transitionProperty a transitionDuration v štýloch a hotovo. Worklets sú imperatívne a dávajú vám frame-by-frame kontrolu, čo potrebujete pre gestá, scroll efekty a interaktívny drag-and-drop. Pre väčšinu bežných UI animácií začnite s CSS prechodmi a siahajte po worklets až keď narazíte na obmedzenia.

Potrebujem Gesture Handler, ak chcem len jednoduché animácie?

Nie. Pre jednoduché animácie ako fade, scale alebo prechody vyvolané tlačidlom vám stačí samotný Reanimated. Gesture Handler potrebujete až vtedy, keď chcete reagovať na ťahanie (pan), štipnutie (pinch), otáčanie (rotation) alebo iné dotykové interakcie.

Funguje Reanimated 4 aj so starou architektúrou React Native?

Bohužiaľ nie. Reanimated 4 vyžaduje výlučne Novú architektúru (Fabric). Ak váš projekt stále beží na starej architektúre, musíte buď migrovať, alebo zostať na Reanimated 3.x. Majte ale na pamäti, že verzia 3.x už nie je aktívne udržiavaná.

Ako animovať vlastný alebo tretí komponent?

Použite funkciu createAnimatedComponent. Obalením ľubovoľného React Native komponentu touto funkciou získate animovateľnú verziu. Reanimated už obsahuje päť vstavaných animovaných komponentov (Animated.View, Animated.Text, Animated.Image, Animated.ScrollView, Animated.FlatList), ostatné si obalíte manuálne.

O Autorovi Editorial Team

Our team of expert writers and editors.