19. Анимации (Animated API)
React Native имеет встроенный Animated API для плавных анимаций. Для сложных — Reanimated 3 (следующий урок).
Animated.Value
Заголовок раздела «Animated.Value»import { Animated } from 'react-native';import { useRef, useEffect } from 'react';
function FadeIn({ children }) { const opacity = useRef(new Animated.Value(0)).current;
useEffect(() => { Animated.timing(opacity, { toValue: 1, duration: 500, useNativeDriver: true, // ОБЯЗАТЕЛЬНО для transform и opacity! }).start(); }, []);
return <Animated.View style={{ opacity }}>{children}</Animated.View>;}Типы анимаций
Заголовок раздела «Типы анимаций»// ЛинейнаяAnimated.timing(value, { toValue: 1, duration: 300, useNativeDriver: true });
// Spring (пружина)Animated.spring(value, { toValue: 1, tension: 40, friction: 7, useNativeDriver: true });
// Decay (затухание)Animated.decay(value, { velocity: 0.5, deceleration: 0.997, useNativeDriver: true });interpolate — маппинг значений
Заголовок раздела «interpolate — маппинг значений»const rotation = opacity.interpolate({ inputRange: [0, 1], outputRange: ['0deg', '360deg'],});
const color = progress.interpolate({ inputRange: [0, 0.5, 1], outputRange: ['#f38ba8', '#f9e2af', '#a6e3a1'],});
<Animated.View style={{ opacity, transform: [{ rotate: rotation }] }} />Последовательные и параллельные
Заголовок раздела «Последовательные и параллельные»// ПоследовательноAnimated.sequence([ Animated.timing(opacity, { toValue: 1, duration: 300, useNativeDriver: true }), Animated.timing(translateY, { toValue: 0, duration: 500, useNativeDriver: true }),]).start();
// ПараллельноAnimated.parallel([ Animated.timing(opacity, { toValue: 1, useNativeDriver: true }), Animated.spring(scale, { toValue: 1, useNativeDriver: true }),]).start();
// Stagger (с задержкой)Animated.stagger(100, items.map(item => Animated.timing(item.opacity, { toValue: 1, useNativeDriver: true }))).start();LayoutAnimation
Заголовок раздела «LayoutAnimation»Автоматически анимирует изменения layout:
import { LayoutAnimation, UIManager, Platform } from 'react-native';
if (Platform.OS === 'android') { UIManager.setLayoutAnimationEnabledExperimental(true);}
function ExpandableCard() { const [expanded, setExpanded] = useState(false);
const toggle = () => { LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut); setExpanded(e => !e); };
return ( <TouchableOpacity onPress={toggle}> <View style={{ height: expanded ? 200 : 80 }}> <Text>Нажми для раскрытия</Text> </View> </TouchableOpacity> );}Loop — бесконечная анимация
Заголовок раздела «Loop — бесконечная анимация»function Spinner() { const rotation = useRef(new Animated.Value(0)).current;
useEffect(() => { Animated.loop( Animated.timing(rotation, { toValue: 1, duration: 1000, useNativeDriver: true }) ).start(); }, []);
const rotate = rotation.interpolate({ inputRange: [0, 1], outputRange: ['0deg', '360deg'], });
return <Animated.View style={{ transform: [{ rotate }] }}><Text>⚙️</Text></Animated.View>;}