Ú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 trvaniawithSpring(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,opacityabackgroundColorje výrazne rýchlejšie ako animovaniewidth,heightalebomargin, 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
Animatedby 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.