Animated API — asoslar

~15 daq · React Native · Animatsiya va UX

Muammodan boshlaylik

Mahsulot savatga qo'shildi — "Qo'shildi ✓" xabari birdan paydo bo'ladi va birdan yo'qoladi. Modal sakrab ochiladi. Ro'yxat elementlari "tarsillab" chiqadi.

Hammasi ishlaydi — lekin "arzon" va qo'pol his qilinadi. Native ilovalarda deyarli hamma narsa harakatlanadi: silliq paydo bo'lish, yumshoq siljish, bosilganda biroz kichrayish. Animatsiya — bezak emas: u foydalanuvchiga nima bo'layotganini tushuntiradi.

React Native da ikki asosiy vosita: o'rnatilgan Animated (bu dars) va Reanimated (keyingi dars).


Asosiy g'oya

Oddiy useState bilan animatsiya qilsangiz — har kadrda (soniyasiga 60 marta) React butun komponentni qayta chizadi. Sekin va uzilib-uzilib.

Animated — maxsus animatsiyalanadigan qiymat va maxsus komponentlar. Qiymat o'zgarganda React qayta chizilmaydi — faqat stil yangilanadi.

import { Animated } from 'react-native';
import { useRef, useEffect } from 'react';

export function PaydoBoluvchi({ children }: { children: React.ReactNode }) {
  const shaffoflik = useRef(new Animated.Value(0)).current;   // 0 dan boshlanadi

  useEffect(() => {
    Animated.timing(shaffoflik, {
      toValue: 1,
      duration: 400,
      useNativeDriver: true,
    }).start();
  }, []);

  return <Animated.View style={{ opacity: shaffoflik }}>{children}</Animated.View>;
}

Uch qadam:

  1. Qiymat — new Animated.Value(0), useRef ichida (har render da qayta yaratilmasin)
  2. Animatsiya — Animated.timing(qiymat, { toValue, duration }) → .start()
  3. Animatsiyalanadigan komponent — Animated.View, Animated.Text, Animated.Image; stilga qiymatni ulash

useNativeDriver: true

useNativeDriver: true

Animatsiya native qatlamda ishlaydi — JavaScript band bo'lsa ham (masalan, katta ro'yxat yuklanmoqda) silliq qoladi.

Cheklov: faqat opacity va transform (siljish, masshtab, burilish) uchun. width, height, backgroundColor, top — useNativeDriver: false bilan, va ular sekinroq.

Qoida: iloji boricha opacity va transform bilan animatsiya qiling — va doim useNativeDriver: true.


Animatsiya turlari

timing — vaqt bo'yicha

import { Easing } from 'react-native';

Animated.timing(qiymat, {
  toValue: 1,
  duration: 300,
  easing: Easing.out(Easing.cubic),     // tez boshlanib, sekin tugaydi
  useNativeDriver: true,
}).start();

Easing — harakat tezligining egri chizig'i. Easing.linear — mexanik va noto'g'ri his qilinadi. Tabiatda hech narsa bir tekis harakatlanmaydi. Easing.out(...) — paydo bo'luvchi elementlar uchun eng tabiiy.

spring — prujina

Animated.spring(masshtab, {
  toValue: 1,
  friction: 5,       // kamroq — ko'proq "sakraydi"
  tension: 80,
  useNativeDriver: true,
}).start();

Davomiylik yo'q — fizika: massa, prujina kuchi, ishqalanish. Natija — tirik va tabiiy. Tugmalar, "yoqtirish" yuragi, kartalar uchun ideal.

decay — sekinlashuvchi

Surilgan elementning inersiya bilan to'xtashi. Asosan imo-ishoralar bilan.


transform

<Animated.View
  style={{
    opacity: shaffoflik,
    transform: [
      { translateY: siljish },         // vertikal siljish
      { scale: masshtab },             // kattalashish
      { rotate: burilish },            // burilish — string kerak: '45deg'
    ],
  }}
/>

interpolate — bitta qiymatdan ko'p effekt

Bitta 0 → 1 qiymatdan bir nechta xususiyatni boshqarish:

const p = useRef(new Animated.Value(0)).current;

const siljish = p.interpolate({ inputRange: [0, 1], outputRange: [40, 0] });
const burilish = p.interpolate({ inputRange: [0, 1], outputRange: ['0deg', '360deg'] });

<Animated.View style={{ opacity: p, transform: [{ translateY: siljish }] }} />

p 0 dan 1 ga o'tganda: element shaffofdan ko'rinadiganga va 40 birlik pastdan joyiga. Bitta animatsiya — ikki effekt, mukammal sinxron.

extrapolate: 'clamp' — qiymat diapazondan chiqsa, natija chegarada qolsin.


Misol: "Savatga qo'shildi" toast

export function Toast({ matn, korinsin }: { matn: string; korinsin: boolean }) {
  const p = useRef(new Animated.Value(0)).current;

  useEffect(() => {
    Animated.spring(p, { toValue: korinsin ? 1 : 0, useNativeDriver: true, friction: 8 }).start();
  }, [korinsin]);

  return (
    <Animated.View
      pointerEvents="none"
      style={{
        position: 'absolute', bottom: 100, alignSelf: 'center',
        backgroundColor: '#0f172a', paddingHorizontal: 20, paddingVertical: 12, borderRadius: 999,
        opacity: p,
        transform: [{ translateY: p.interpolate({ inputRange: [0, 1], outputRange: [20, 0] }) }, { scale: p.interpolate({ inputRange: [0, 1], outputRange: [0.9, 1] }) }],
      }}
    >
      <Text style={{ color: 'white', fontWeight: '600' }}>{matn}</Text>
    </Animated.View>
  );
}

Animatsiyalarni birlashtirish

Animated.sequence([                        // ketma-ket
  Animated.timing(a, { toValue: 1, duration: 200, useNativeDriver: true }),
  Animated.delay(1500),
  Animated.timing(a, { toValue: 0, duration: 200, useNativeDriver: true }),
]).start();

Animated.parallel([...]).start();          // bir vaqtda

Animated.stagger(60, elementlar.map((v) =>  // har biri 60 ms kechikish bilan — "to'lqin"
  Animated.timing(v, { toValue: 1, duration: 300, useNativeDriver: true })
)).start();

Animated.loop(Animated.timing(...)).start();   // cheksiz — yuklanish belgisi

Scroll bilan bog'lash

Scroll qilganda sarlavha kichrayadi yoki shaffoflanadi:

const scrollY = useRef(new Animated.Value(0)).current;
const sarlavhaShaffoflik = scrollY.interpolate({ inputRange: [0, 120], outputRange: [0, 1], extrapolate: 'clamp' });

<Animated.ScrollView
  onScroll={Animated.event([{ nativeEvent: { contentOffset: { y: scrollY } } }], { useNativeDriver: true })}
  scrollEventThrottle={16}
>

Animated.event — scroll pozitsiyasini to'g'ridan-to'g'ri animatsiya qiymatiga yozadi, JavaScript siz.


Oddiy holatlar uchun: LayoutAnimation

Ro'yxatga element qo'shildi yoki o'chirildi — qolganlar birdan siljiydi. Bitta qator bilan silliq qilish:

import { LayoutAnimation } from 'react-native';

function ochir(id: number) {
  LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut);
  setRoyxat((r) => r.filter((x) => x.id !== id));
}

Keyingi layout o'zgarishi avtomatik animatsiya qilinadi. Cheklangan nazorat, lekin minimal kod.


Nima uchun shunday?

Nima uchun animatsiya qiymatlari React holatidan (useState) alohida?

Chunki React ning qayta chizish mexanizmi animatsiya uchun juda og'ir. 60 kadr/soniyada har bir kadr uchun 16 ms bor. setState — komponentni qayta chizish, virtual daraxtni solishtirish, native qatlamga yuborish — ko'pincha 16 ms dan ko'p. Animated qiymat esa React ni chetlab o'tadi: u faqat bitta stil xususiyatini to'g'ridan-to'g'ri yangilaydi, useNativeDriver bilan esa butun animatsiya native tomonda boshlanib, JavaScript ga umuman bog'liq bo'lmaydi.


Xulosa

Eslab qoling:

  • useRef(new Animated.Value(0)).current — qiymat
  • Animated.timing (vaqt + easing), Animated.spring (fizika) → .start()
  • Animated.View + stilga qiymat
  • useNativeDriver: true — faqat opacity va transform, lekin silliq
  • interpolate — bitta qiymatdan ko'p effekt; extrapolate: 'clamp'
  • sequence, parallel, stagger, loop — birlashtirish
  • Animated.event — scroll bilan bog'lash
  • LayoutAnimation — ro'yxat o'zgarishlari uchun eng oddiy yo'l

Keyingi dars

45-dars: Reanimated — silliq animatsiyalar