24 β Animatsiya va gestlar¶
β¬ οΈ Oldingi: 23 β Bildirishnoma va sensorlar Β· π Kitob boshi Β· Keyingi: 25 β Autentifikatsiya β‘οΈ
Bu bobda: Ilovangizni jonli va silliq qiladigan ikki sehrli kuchni o'rganamiz: animatsiya (elementlar yumshoq paydo bo'ladi, kattalashadi, suriladi) va gestlar (barmoq harakatlarini tushunish β surish, chimchilab cho'zish, uzoq bosish). Avval RN'ning o'rnatilgan
Animatedvositasini ko'ramiz, keyin zamonaviy va silliq Reanimatedni hamda gesture-handler kutubxonasini chuqur o'rganamiz. Oxirida ikkalasini birlashtirib, bosilganda kattalashadigan tugma va surib o'chiriladigan ro'yxat yasaymiz.
Animatsiya nega kerak?¶
Tasavvur qiling, devorda ikkita rasm bor. Birinchisi β bitta qotib qolgan, qimirlamaydigan surat. Ikkinchisi β jonli multfilm bo'lagi: personajlar harakatlanadi, ranglar yumshoq o'tadi, hamma narsa nafas oladigandek tuyuladi. Qaysi biri sizni ko'proq jalb qiladi? Albatta, ikkinchisi.
Mobil ilovada ham xuddi shunday. Tugma bosilganda u shunchaki "qars" deb o'zgarsa β ilova qo'pol va arzon his qildiradi. Ammo o'sha tugma bosilganda sal kattalashib, keyin yumshoq joyiga qaytsa β ilova qimmatbaho va o'ylangan tuyuladi. Animatsiya β bu bezak emas, balki uchta muhim vazifani bajaradi:
- Silliq o'tishlar. Bir holatdan ikkinchisiga keskin "sakrash" emas, balki ko'z kuzata oladigan yumshoq yo'l. Ekran o'zgargani sezilmasdan amalga oshadi.
- Jonli his. Ilova "tirik" tuyuladi. Element paydo bo'lganda silliq suzib chiqsa, foydalanuvchi miyasi buni tabiiy deb qabul qiladi.
- Foydalanuvchi e'tiborini boshqarish. Animatsiya ko'zni kerakli joyga yo'naltiradi: yangi xabar qalqib chiqsa, xato qizarib silkinasa β foydalanuvchi nimaga e'tibor berishni darhol tushunadi.
Hayotiy o'xshatish. Animatsiyasiz ilova β bu qotib qolgan rasm. Animatsiyali ilova β bu jonli multfilm. Bir xil sahna, lekin ikkinchisi sizni ekranga mixlab qo'yadi. Sirning kaliti β harakatning silliqligi: agar multfilm sekundiga 60 marta yangilanmasa (ya'ni "to'xtab-to'xtab" ketsa), sehr buziladi. Shu sababli biz qaysi vositani tanlashga juda jiddiy qaraymiz.
Bu bobda animatsiyaning ikki vositasini ko'ramiz. Animated β RN'ning o'rnatilgan, oddiy vositasi. Reanimated β zamonaviy, eng silliq va kuchli kutubxona. Ikkalasini ham o'rganamiz, lekin kun bo'yi ishlaydigan asosiy quroling Reanimated bo'ladi.
Animated β RN'ning o'rnatilgan vositasi¶
RN'ning ichida Animated degan tayyor vosita bor. Hech narsa o'rnatmasdan, oddiy animatsiyalarni qila olasiz. U uchta asosiy qismdan iborat:
Animated.Valueβ animatsiyalanadigan qiymat (masalan, shaffoflik 0 dan 1 gacha). UniuseRefichida saqlaymiz, chunki u render orasida buzilmasligi kerak.Animated.timing/Animated.springβ qiymatni qanday o'zgartirish (vaqt bo'yicha tekis, yoki prujinadek sakrab).Animated.Viewβ animatsiyalanadigan qiymatni qabul qila oladigan maxsusView.
Mana oddiy fade-in (yumshoq paydo bo'lish) misoli:
// app/fade-animated.tsx
import { useRef } from 'react';
import { Animated, Pressable, Text } from 'react-native';
export default function FadeAnimated() {
// Shaffoflik qiymati: 0 = ko'rinmas, 1 = to'liq ko'rinadi
const ozuvchanlik = useRef(new Animated.Value(0)).current;
function korsat() {
Animated.timing(ozuvchanlik, {
toValue: 1, // qayerga: to'liq ko'rinishga
duration: 500, // 500 millisekundda
useNativeDriver: true, // MUHIM: native ipda ishlasin (silliqroq)
}).start(); // animatsiyani boshlaymiz
}
return (
<Animated.View style={{ opacity: ozuvchanlik }}>
<Pressable onPress={korsat}>
<Text>Salom! Meni paydo qiling.</Text>
</Pressable>
</Animated.View>
);
}
Bu yerdagi eng muhim narsa β useNativeDriver: true. U animatsiyani imkon qadar native (mahalliy) tomonga uzatadi, shunda u silliqroq ishlaydi.
Ehtiyot bo'ling
useNativeDriver: true faqat ba'zi xususiyatlar uchun ishlaydi: opacity va transform (siljish, aylanish, masshtab). width, height, backgroundColor kabi tarkib (layout) xususiyatlarini native driver animatsiyalay olmaydi β ularda useNativeDriver: false bo'ladi, lekin u sekinroq.
Animated oddiy vazifalar uchun yaxshi. Ammo zamonaviy RN dunyosida murakkab va silliq animatsiyalar uchun barcha mutaxassislar Reanimatedni ishlatadi. Endi asosiy mavzuga o'tamiz.
Reanimated β zamonaviy va silliq animatsiya¶
Reanimated (react-native-reanimated, hozirgi versiya 4.x) β bu animatsiya uchun eng kuchli va eng silliq kutubxona. U RN'ning o'rnatilgan Animated vositasidan nimasi bilan yaxshi? U animatsiyani UI (ko'rinish) ip-tolasida (thread) bajaradi β buni tez orada batafsil tushuntiramiz, hozircha "u har doim silliq" deb yeting.
Bu kitobning Drawer navigatsiyasi (15-bob) allaqachon Reanimated'ga tayanadi, shuning uchun u odatda loyihangizda o'rnatilgan bo'ladi. Yangi loyihada o'rnatish:
Reanimated'ning to'rtta asosiy g'ishti bor. Ularni yaxshilab eslab qoling β qolgan hamma narsa shulardan quriladi:
| G'isht | Vazifasi |
|---|---|
useSharedValue(0) |
Animatsiyalanadigan qiymat (boshlang'ich 0) |
useAnimatedStyle(() => ({...})) |
Qiymatni stilga bog'laydi |
withTiming / withSpring |
Qiymatni qanday o'zgartirish |
<Animated.View> |
Animatsiyalangan stilni qabul qiladigan View |
Hayotiy o'xshatish.
useSharedValueβ bu lift tugmasi bosilgan qavat raqami.useAnimatedStyleβ bu liftning o'zi (raqamga qarab qaysi qavatga borishni biladi).withTimingesa β lift qanday harakatlanishi (tekis-yumshoq, yoki "ding!" deb prujinadek). Siz faqat qavat raqamini o'zgartirasiz β qolganini Reanimated o'zi silliq bajaradi.
useSharedValue β animatsiya qiymati¶
Shared value (ya'ni "umumiy qiymat") β bu animatsiyaning yuragi. U useStatega o'xshaydi, lekin bitta katta farqi bor: uni o'zgartirsangiz, komponent qayta render bo'lmaydi. O'zgarish to'g'ridan-to'g'ri ekranga, qayta render qilishsiz yetib boradi β shuning uchun u juda tez.
import { useSharedValue } from 'react-native-reanimated';
const ozuvchanlik = useSharedValue(0); // boshlang'ich qiymat 0
Qiymatni o'qish va yozish uchun har doim .value ishlatamiz:
Eng keng tarqalgan xato
.valueni unutmang! ozuvchanlik = 1 deb yozsangiz ishlamaydi β bu shared value'ni butunlay buzadi. Har doim ozuvchanlik.value = 1.
useAnimatedStyle β qiymatni stilga bog'lash¶
Animated style β bu shared value'ni komponent stiliga ulaydigan ko'prik. U funksiya qabul qiladi va o'sha funksiya stil obyektini qaytaradi:
const uslub = useAnimatedStyle(() => ({
opacity: ozuvchanlik.value, // shared value o'zgarsa, opacity ham o'zgaradi
}));
Endi uslubni Animated.Viewga beramiz. ozuvchanlik.value har safar o'zgarganda, bu stil avtomatik yangilanadi.
withTiming va withSpring β qiymatni qanday o'zgartirish¶
Agar shunchaki ozuvchanlik.value = 1 desangiz, qiymat darhol sakraydi β animatsiya bo'lmaydi. Silliq o'tish uchun qiymatni animatsiya funksiyasiga o'rab beramiz:
withTiming(maqsad, { duration })β qiymatni belgilangan vaqtda tekis o'zgartiradi. Fade, siljish uchun ideal.withSpring(maqsad)β qiymatni prujinadek o'zgartiradi: maqsadga yetib, biroz "sakrab" qaytadi. Tugma bosish, kartochka paydo bo'lishi uchun jonli his beradi.
ozuvchanlik.value = withTiming(1, { duration: 300 }); // 300ms da tekis
olcham.value = withSpring(1.2); // prujinadek
To'liq fade-in misoli¶
Endi hammasini birlashtiramiz. Tugma bosilsa, matn yumshoq paydo bo'ladi:
// app/reanimated-fade.tsx
import Animated, {
useSharedValue,
useAnimatedStyle,
withTiming,
} from 'react-native-reanimated';
import { Pressable, Text, StyleSheet } from 'react-native';
export default function ReanimatedFade() {
const ozuvchanlik = useSharedValue(0); // 1. qiymat
// 2. qiymatni stilga bog'laymiz
const uslub = useAnimatedStyle(() => ({ opacity: ozuvchanlik.value }));
// 3. tugma bosilsa qiymatni silliq 1 ga olib boramiz
function korsat() {
ozuvchanlik.value = withTiming(1, { duration: 300 });
}
return (
<Animated.View style={[styles.quti, uslub]}>
<Pressable onPress={korsat}>
<Text style={styles.matn}>Men yumshoq paydo bo'laman</Text>
</Pressable>
</Animated.View>
);
}
const styles = StyleSheet.create({
quti: { padding: 20, backgroundColor: '#fff', borderRadius: 12 },
matn: { fontSize: 16, color: '#1e293b' },
});
Import nomi
Reanimated'ning Animated obyektini default import bilan olamiz: import Animated from 'react-native-reanimated'. Bu RN'ning o'z Animatedidan boshqa narsa! Ataylab Reanimated deb nomlasangiz ham bo'ladi: import Reanimated from 'react-native-reanimated'. Bu kitobda qisqalik uchun Animated deb yozamiz.
Yana foydali animatsiya funksiyalari¶
Bu to'rttasini ham bilib qo'ying β ular bilan murakkab animatsiyalarni quchaqlaysiz:
import {
withDelay, withRepeat, withSequence, Easing,
} from 'react-native-reanimated';
// 200ms kutib, keyin animatsiya boshlash:
x.value = withDelay(200, withTiming(100));
// Animatsiyani 3 marta takrorlash (true = oldinga-orqaga):
x.value = withRepeat(withTiming(50, { duration: 300 }), 3, true);
// Ketma-ket bir nechta animatsiya (silkinish effekti):
x.value = withSequence(withTiming(20), withTiming(-20), withTiming(0));
// Easing β harakat "tezlanishi" egri chizig'i:
x.value = withTiming(1, { duration: 400, easing: Easing.out(Easing.quad) });
withSequence bilan, masalan, xato kiritilganda inputni chap-o'ng silkitish mumkin. withRepeat esa "yuklanmoqda" indikatorini abadiy aylantirish uchun zo'r.
Nega Reanimated shunchalik silliq? (ip-tolalar)¶
Bu eng muhim tushuncha β uni bilsangiz, qachon nimani ishlatishni bilasiz. 1-bobda biz JSI (JavaScript Interface) haqida gaplashgandik: New Architecture'da JS bilan native qatlam to'g'ridan-to'g'ri gaplashadi. Reanimated aynan shu imkoniyatga tayanadi.
RN ilovasida ikkita asosiy "ishchi yo'lak" (thread, ya'ni ip-tola) bor:
- JS ip-tolasi β sizning butun JavaScript kodingiz shu yerda ishlaydi: holat,
useEffect, API so'rovlar, ro'yxatni hisoblash... - UI ip-tolasi β ekranni chizadigan native qatlam. U sekundiga 60 (yoki 120) marta kadr chizadi.
Endi muammoni tasavvur qiling. Eski Animatedda animatsiya JS ip-tolasida hisoblanadi. Agar shu paytda JS ip-tolasi band bo'lsa (masalan, katta ro'yxatni saralayapti yoki API javobini qayta ishlayapti) β animatsiya to'xtab-to'xtab ketadi. Multfilm "lag" qiladi.
Reanimated bu muammoni qoyilmaqom hal qiladi: u animatsiya kodini (useAnimatedStyle ichidagi funksiyani) UI ip-tolasiga ko'chiradi. Endi JS ip-tolasi nima bilan band bo'lishidan qat'i nazar, animatsiya alohida yo'lakda, har doim silliq ishlaydi.
Hayotiy o'xshatish. Tasavvur qiling, restoran bor. Bitta ofitsiant ham buyurtma oladi, ham ovqat tashiydi, ham hisob yozadi β band paytda hamma narsa sekinlashadi (eski Animated, bitta JS ip-tolasi). Reanimated esa animatsiya uchun alohida ofitsiant yollaydi: u faqat "harakatni silliq olib borish" bilan shug'ullanadi. Asosiy ofitsiant qanchalik band bo'lmasin, animatsiya ofitsianti to'xtamaydi.
Worklet β UI ipida ishlaydigan kod
useAnimatedStyle va gest onUpdate ichidagi funksiyalar worklet deb ataladi β ular JS ip-tolasida emas, UI ip-tolasida ishlaydi. Reanimated buni avtomatik tashkil qiladi (Worklets kutubxonasi orqali). Worklet ichidan oddiy JS funksiyangizni (masalan, setState) chaqirmoqchi bo'lsangiz, runOnJS kerak bo'ladi β buni gestlar bo'limida ko'ramiz.
Gestlar β barmoq harakatlarini tushunish¶
Animatsiya β bu yarmi. Ikkinchi yarmi β gestlar: foydalanuvchining barmog'i ekranda nima qilayotganini tushunish. Surish, chimchilab cho'zish, uzoq bosish... Bularni react-native-gesture-handler kutubxonasi boshqaradi (qisqacha GH). U ham Drawer (15-bob) tufayli odatda allaqachon o'rnatilgan.
Ildizda GestureHandlerRootView¶
Gestlar ishlashi uchun butun ilovani GestureHandlerRootView bilan o'rab qo'yish kerak β bu bir martalik sozlash. Odatda buni ildiz _layout.tsxda qilamiz:
// app/_layout.tsx
import { GestureHandlerRootView } from 'react-native-gesture-handler';
import { Stack } from 'expo-router';
export default function RootLayout() {
return (
<GestureHandlerRootView style={{ flex: 1 }}>
<Stack />
</GestureHandlerRootView>
);
}
Eng keng tarqalgan xato
GestureHandlerRootView ildizda bo'lmasa, gestlaringiz jimgina ishlamaydi β xato ham chiqmaydi. Agar surishlaringiz "ta'sir qilmayotgan" bo'lsa, birinchi navbatda shuni tekshiring.
GestureDetector + Gesture β to'rtta asosiy gest¶
Zamonaviy GH'ning ishlash uslubi sodda: gestni Gesture.Xxx() bilan yaratasiz, sozlaysiz, keyin uni <GestureDetector gesture={...}> bilan biror elementga "yopishtirib" qo'yasiz. To'rtta eng ko'p ishlatiladigan gest:
| Gest | Nima qiladi |
|---|---|
Gesture.Pan() |
Surish β barmoqni siljitish (eng ko'p ishlatiladi) |
Gesture.Tap() |
Bir bosish β tez tegib olish |
Gesture.Pinch() |
Chimchilab cho'zish β ikki barmoq bilan kattalashtirish |
Gesture.LongPress() |
Uzoq bosib turish β kontekst menyu, tanlash |
Har bir gestning "tinglovchilari" (callback'lari) bor. Eng muhimlari: .onBegin (gest boshlandi), .onUpdate (barmoq harakatlanmoqda β har kadrda chaqiriladi), .onEnd (barmoq ko'tarildi). Mana Tap, LongPress va Pinch'ning oddiy ko'rinishi:
import { GestureDetector, Gesture } from 'react-native-gesture-handler';
import { View, Text } from 'react-native';
const tap = Gesture.Tap().onEnd(() => {
console.log('Bir marta bosildi');
});
const uzunBosish = Gesture.LongPress().onStart(() => {
console.log('Uzoq bosildi β menyu ochsa bo\'ladi');
});
const pinch = Gesture.Pinch().onUpdate((e) => {
console.log('Cho\'zish masshtabi:', e.scale); // e.scale β necha barobar
});
Ko'rib turganingizdek, onUpdate callback'i hodisa obyekti (e) qabul qiladi β unda gest haqida hamma ma'lumot bor: e.translationX/Y (Pan uchun qancha surilgan), e.scale (Pinch masshtabi) va hokazo. Endi eng qiziq qismga β Pan gestini animatsiya bilan birlashtirishga o'tamiz.
Gest + animatsiya birga: surilgan kartochka¶
Mana sehr boshlanadigan joy. Pan gesti barmoq qancha surilganini beradi, shared value uni saqlaydi, animated style esa elementni o'sha joyga ko'chiradi. Natijada β barmoq orqasidan ergashadigan, suriladigan kartochka.
// app/surilgan-karta.tsx
import Animated, {
useSharedValue, useAnimatedStyle,
} from 'react-native-reanimated';
import { GestureDetector, Gesture } from 'react-native-gesture-handler';
import { Text, StyleSheet } from 'react-native';
export default function SurilganKarta() {
const x = useSharedValue(0); // gorizontal siljish
const y = useSharedValue(0); // vertikal siljish
const boshX = useSharedValue(0); // surish boshlangandagi joy
const boshY = useSharedValue(0);
const pan = Gesture.Pan()
.onBegin(() => {
// surish boshlanganda hozirgi joyni eslab qolamiz
boshX.value = x.value;
boshY.value = y.value;
})
.onUpdate((e) => {
// boshlang'ich joy + barmoq qancha surilgani
x.value = boshX.value + e.translationX;
y.value = boshY.value + e.translationY;
});
const uslub = useAnimatedStyle(() => ({
transform: [
{ translateX: x.value },
{ translateY: y.value },
],
}));
return (
<GestureDetector gesture={pan}>
<Animated.View style={[styles.karta, uslub]}>
<Text style={styles.matn}>Meni istalgan joyga suring</Text>
</Animated.View>
</GestureDetector>
);
}
const styles = StyleSheet.create({
karta: { padding: 24, backgroundColor: '#0ea5e9', borderRadius: 16 },
matn: { color: '#fff', fontSize: 16, fontWeight: '600' },
});
Diqqat qiling: onBeginda boshlang'ich joyni eslab qolamiz, onUpdateda esa boshlang'ich + siljish deb hisoblaymiz. Agar buni qilmasak, har gal surishni boshlaganda kartochka 0 ga "sakraydi". Bu β draggable (sudralib yuradigan) element yasashning standart usuli.
runOnJS β worklet'dan oddiy kodga ko'prik¶
Esda tutasizmi, gest callback'lari worklet β ular UI ip-tolasida ishlaydi. Agar surish tugaganda oddiy JS funksiyangizni (masalan, setState yoki navigatsiya) chaqirmoqchi bo'lsangiz, to'g'ridan-to'g'ri chaqira olmaysiz β kerak runOnJS ko'prigi:
import { runOnJS } from 'react-native-reanimated';
const pan = Gesture.Pan().onEnd(() => {
// 'use worklet' β bu UI ipida ishlaydi
runOnJS(menimFunksiyam)(); // oddiy JS funksiyani xavfsiz chaqiramiz
});
Hayotiy o'xshatish. Worklet (UI ipi) va oddiy JS kodi β bu ikki xil tilda gaplashadigan ikki bo'lim kabi.
runOnJSβ ular orasidagi tarjimon: "men (UI ipi) JS bo'limiga xabar yubormoqchiman" deganingizda, xabarnirunOnJSga o'rab berasiz, u to'g'ri yetkazadi.
Swipe-to-delete: surib o'chirish¶
Endi runOnJSni amalda ko'ramiz β bu eng mashhur naqsh: ro'yxat elementini chapga surib o'chirish. Mantiq oddiy: agar foydalanuvchi yetarlicha uzoq surib (masalan, 120 dp chapga) qo'lini ko'tarsa, elementni o'chiramiz. Aks holda, element joyiga qaytadi.
// app/swipe-ochirish.tsx
import Animated, {
useSharedValue, useAnimatedStyle, withTiming, withSpring, runOnJS,
} from 'react-native-reanimated';
import { GestureDetector, Gesture } from 'react-native-gesture-handler';
import { Text, StyleSheet } from 'react-native';
type Props = { nomi: string; onOchir: () => void };
export default function SwipeOchirish({ nomi, onOchir }: Props) {
const x = useSharedValue(0);
const pan = Gesture.Pan()
.onUpdate((e) => {
x.value = e.translationX; // barmoq orqasidan suriladi
})
.onEnd(() => {
if (x.value < -120) {
// yetarlicha chapga surilgan β ekrandan chiqarib o'chiramiz
x.value = withTiming(-400, { duration: 200 });
runOnJS(onOchir)(); // ro'yxatdan o'chiruvchi JS funksiya
} else {
// yetmadi β silliq joyiga qaytaradi
x.value = withSpring(0);
}
});
const uslub = useAnimatedStyle(() => ({
transform: [{ translateX: x.value }],
}));
return (
<GestureDetector gesture={pan}>
<Animated.View style={[styles.karta, uslub]}>
<Text style={styles.matn}>{nomi}</Text>
</Animated.View>
</GestureDetector>
);
}
const styles = StyleSheet.create({
karta: {
padding: 18, backgroundColor: '#fff', borderRadius: 12,
marginVertical: 6, borderWidth: 1, borderColor: '#e2e8f0',
},
matn: { fontSize: 16, color: '#1e293b' },
});
Bu yerda runOnJS(onOchir)() ota komponentdagi setStateni chaqiradi β u ro'yxatdan elementni olib tashlaydi. Agar runOnJSsiz to'g'ridan-to'g'ri onOchir() desangiz, ilova worklet ichida xato beradi.
Tayyor yechim ham bor
O'zingiz Pan bilan swipe yozish β o'rganish uchun zo'r. Lekin amaliyotda react-native-gesture-handler'ning o'zida Swipeable komponenti bor (react-native-gesture-handler dan import qilinadi), u chap/o'ng harakatlarni tayyor beradi. Mantiqni tushungandan keyin tayyorini ishlatish β aqlli yo'l.
Layout animatsiyalari β eng oson sehr¶
Yuqorida biz qiymatlarni qo'lda animatsiya qildik. Lekin Reanimated yana bir ajoyib imkoniyat beradi: layout animatsiyalari. Bu eng oson va eng kuchli vosita. Element ro'yxatga qo'shilganda yoki undan o'chirilganda β Reanimated avtomatik silliq animatsiya qiladi. Sizdan deyarli hech narsa talab qilinmaydi!
Uchta xususiyat bor, ularni to'g'ridan-to'g'ri Animated.Viewga berasiz:
entering={FadeIn}β element ekranga qo'shilganda qanday paydo bo'ladi.exiting={FadeOut}β element o'chirilganda qanday yo'qoladi.layout={LinearTransition}β qolgan elementlar joyi o'zgarganda silliq surilishi.
// app/layout-animatsiya.tsx
import Animated, {
FadeIn, FadeOut, LinearTransition,
} from 'react-native-reanimated';
import { FlatList, Text, StyleSheet } from 'react-native';
type Vazifa = { id: string; nomi: string };
export default function LayoutMisol({ vazifalar }: { vazifalar: Vazifa[] }) {
return (
<FlatList
data={vazifalar}
keyExtractor={(v) => v.id}
renderItem={({ item }) => (
<Animated.View
entering={FadeIn} // qo'shilganda yumshoq paydo
exiting={FadeOut} // o'chirilganda yumshoq yo'qoladi
layout={LinearTransition} // qolganlar silliq suriladi
style={styles.karta}
>
<Text style={styles.matn}>{item.nomi}</Text>
</Animated.View>
)}
/>
);
}
const styles = StyleSheet.create({
karta: { padding: 16, backgroundColor: '#fff', borderRadius: 12, marginVertical: 6 },
matn: { fontSize: 16, color: '#1e293b' },
});
Endi vazifalar ro'yxatiga element qo'shsangiz β u yumshoq suzib chiqadi; o'chirsangiz β yumshoq so'nadi; qolganlar esa silliq surilib bo'sh joyni egallaydi. Hammasi avtomatik!
Boshqa tayyor presetlar
FadeIn/FadeOutdan tashqari ko'plab tayyor presetlar bor: SlideInLeft, SlideOutRight, ZoomIn, ZoomOut, BounceIn va boshqalar. Ularni react-native-reanimateddan import qilib, sinab ko'ring. Davomiyligini sozlash: entering={FadeIn.duration(400)}.
Tayyor kutubxonalar¶
Reanimated va gesture-handler β bu poydevor. Ular ustiga qurilgan tayyor yechimlar ham bor:
react-native-reanimatedβ animatsiya va gest mantig'ining asosi. Deyarli har bir jiddiy RN ilovasi unga tayanadi.motiβ Reanimated ustiga qurilgan, juda qisqa sintaksisli kutubxona.<MotiView from={{ opacity: 0 }} animate={{ opacity: 1 }} />βuseSharedValue/useAnimatedStyleyozmasdan animatsiya. Tez prototip uchun qulay. Lekin avval poydevorni (Reanimated) tushunish muhim β keyinmotifaqat qisqartma bo'ladi.
Maslahat
Yangi loyihada animatsiya kerak bo'lsa: oddiy paydo bo'lish/o'chish uchun β layout animatsiyalar (FadeIn/FadeOut). Interaktiv (surish, masshtab) uchun β Reanimated + gesture-handler. Juda tez prototip uchun β moti. Eski Animatedni faqat juda oddiy holatlarda ishlatish kifoya.
To'liq misol: kattalashadigan tugma + surib o'chiriladigan ro'yxat¶
Endi bobning toji β o'rganganlarimizni bitta ishlaydigan ekranda birlashtiramiz. Bunda ikki narsa bor:
- Bosilganda kattalashadigan tugma (
withSpringbilan). - Surib o'chiriladigan ro'yxat (
Gesture.Pan+runOnJS+ layout animatsiya).
Avval kattalashadigan tugma. Barmoq tushganda (onPressIn) tugma sal kattalashadi, ko'tarilganda (onPressOut) prujinadek joyiga qaytadi:
// app/prujina-tugma.tsx
import Animated, {
useSharedValue, useAnimatedStyle, withSpring,
} from 'react-native-reanimated';
import { Pressable, Text, StyleSheet } from 'react-native';
export default function PrujinaTugma() {
const olcham = useSharedValue(1); // masshtab: 1 = oddiy o'lcham
const uslub = useAnimatedStyle(() => ({
transform: [{ scale: olcham.value }],
}));
return (
<Animated.View style={uslub}>
<Pressable
onPressIn={() => { olcham.value = withSpring(1.15); }} // bosilganda kattalashadi
onPressOut={() => { olcham.value = withSpring(1); }} // qo'yib yuborilganda qaytadi
style={styles.tugma}
>
<Text style={styles.tugmaMatn}>Bos meni</Text>
</Pressable>
</Animated.View>
);
}
const styles = StyleSheet.create({
tugma: { backgroundColor: '#4f46e5', paddingVertical: 14, paddingHorizontal: 32, borderRadius: 12 },
tugmaMatn: { color: '#fff', fontSize: 16, fontWeight: '700' },
});
Endi bularning hammasini bitta ekranga yig'amiz. Yuqoridagi SwipeOchirish va PrujinaTugma komponentlarini ishlatamiz, ro'yxatga esa layout animatsiya beramiz:
// app/animatsiya-demo.tsx
import { useState } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import Animated, { LinearTransition } from 'react-native-reanimated';
import PrujinaTugma from './prujina-tugma';
import SwipeOchirish from './swipe-ochirish';
type Vazifa = { id: string; nomi: string };
export default function AnimatsiyaDemo() {
const [vazifalar, setVazifalar] = useState<Vazifa[]>([
{ id: '1', nomi: 'Sut sotib olish' },
{ id: '2', nomi: 'Kitob o\'qish' },
{ id: '3', nomi: 'Mashq qilish' },
]);
function qoshish() {
const yangi = { id: Date.now().toString(), nomi: 'Yangi vazifa' };
setVazifalar((oldin) => [yangi, ...oldin]);
}
function ochir(id: string) {
setVazifalar((oldin) => oldin.filter((v) => v.id !== id));
}
return (
<View style={styles.box}>
<Text style={styles.sarlavha}>Vazifalar</Text>
<PrujinaTugma />
{/* layout animatsiya bilan ro'yxat β har bir element suriladi/silliq paydo bo'ladi */}
{vazifalar.map((v) => (
<Animated.View key={v.id} layout={LinearTransition}>
<SwipeOchirish nomi={v.nomi} onOchir={() => ochir(v.id)} />
</Animated.View>
))}
{vazifalar.length === 0 && (
<Text style={styles.bosh}>Hammasi bajarildi!</Text>
)}
</View>
);
}
const styles = StyleSheet.create({
box: { flex: 1, padding: 20, gap: 14, justifyContent: 'center' },
sarlavha: { fontSize: 24, fontWeight: '700', color: '#1e293b' },
bosh: { fontSize: 16, color: '#94a3b8', textAlign: 'center' },
});
Bu ekranda: tugma bosilganda kattalashadi (withSpring), elementlarni chapga surib o'chirasiz (Pan + runOnJS), o'chgan element silliq ketadi va qolganlar avtomatik suriladi (LinearTransition). Esda tutilsin β bularning bari ishlashi uchun ildizda GestureHandlerRootView bo'lishi shart.
Tekshirilgan
Bu bobdagi barcha kod namunalari β Animated, Reanimated (useSharedValue/useAnimatedStyle/withTiming/withSpring/withDelay/withRepeat/withSequence/Easing), gesture-handler (Gesture.Pan/Tap/Pinch/LongPress/GestureDetector), runOnJS va layout animatsiyalar (FadeIn/FadeOut/LinearTransition) β real Expo loyihasida (Reanimated 4.x, gesture-handler 2.x) npx tsc --noEmit bilan xatosiz tekshirildi.
Xulosa¶
- Animatsiya ilovani jonli va qimmatbaho qiladi: silliq o'tishlar, jonli his, foydalanuvchi e'tiborini boshqarish. "Qotgan rasm vs jonli multfilm".
Animatedβ RN'ning o'rnatilgan, oddiy vositasi:Animated.Value+Animated.timing/spring+Animated.View+useNativeDriver: true. Oddiy fade/slide uchun yetadi.- Reanimated (zamonaviy, asosiy) to'rt g'ishtdan iborat:
useSharedValue(qiymat),useAnimatedStyle(stilga bog'lash),withTiming/withSpring(qanday o'zgarish),Animated.View(ko'rsatish). Shared value.valueorqali ishlaydi va qayta render qilmaydi. - Nega silliq: Reanimated animatsiyani UI ip-tolasida (worklet) bajaradi β JS ip-tolasi band bo'lsa ham silliq. Bu New Architecture'ning JSI imkoniyatiga tayanadi.
react-native-gesture-handler:Gesture.Pan()(surish),.Tap(),.Pinch()(cho'zish),.LongPress(); ularni<GestureDetector>elementga bog'laydi. IldizdaGestureHandlerRootViewshart.- Gest + animatsiya birga: Pan'ning
e.translationX/Yni shared value'ga yozib,useAnimatedStyle'datranslateX/Yqilamiz β draggable, swipe-to-delete chiqadi. Worklet'dan JS funksiyani chaqirish uchunrunOnJS. - Layout animatsiyalari β eng oson kuch:
entering={FadeIn},exiting={FadeOut},layout={LinearTransition}β element qo'shil/o'chirilganda avtomatik silliq animatsiya. - Tayyor kutubxonalar: poydevor β
react-native-reanimated; tez prototip uchun qisqa sintaksislimoti.
Amaliy mashqlar¶
-
Fade-in salom. Ekran ochilganda matn 0 dan to'liq ko'rinishga yumshoq chiqsin.
useSharedValue(0)+useAnimatedStyle(opacity) +useEffectichidawithTiming(1). Yo'naltirish:useEffect(() => { ozuvchanlik.value = withTiming(1, { duration: 600 }); }, []). -
Kattalashadigan tugma. Bosilganda 1.15 barobar kattalashib, qo'yib yuborilganda joyiga qaytadigan tugma yasang (
withSpring). Yo'naltirish:PressableningonPressIn/onPressOutdaolcham.valueni o'zgartiring; stilgatransform: [{ scale }]. -
Surib o'chirish. Bitta kartochkani chapga surib o'chirib bo'ladigan qiling. 120 dp dan ko'p surilsa o'chsin, aks holda joyiga qaytsin. Yo'naltirish:
Gesture.Pan().onUpdate(...).onEnd(...); o'chirish uchunrunOnJS(onOchir)(); qaytarish uchunwithSpring(0). -
Layout animatsiya ro'yxati. "Qo'shish" tugmasi bosilganda ro'yxatga yangi element yumshoq qo'shilsin, o'chirilganda yumshoq ketsin. Yo'naltirish: har elementni
<Animated.View entering={FadeIn} exiting={FadeOut} layout={LinearTransition}>bilan o'rang; ro'yxatniuseStatebilan boshqaring. -
Suriladigan kartochka (qiyin). Ekran bo'ylab istalgan joyga sudralib yuradigan kartochka yasang. Surish tugaganda u eng yaqin chetga (chap yoki o'ng) prujinadek "yopishsin". Yo'naltirish:
x/yshared value;onBeginda boshlang'ich joyni eslang;onEnddax.value < ekranKengligi/2 ? withSpring(0) : withSpring(maxX). -
Pinch bilan rasm cho'zish (qiyin). Bir rasmni ikki barmoq bilan chimchilab kattalashtirib/kichraytiring (
Gesture.Pinch). Yo'naltirish:olcham.valuenie.scalega bog'lang;onEnddawithSpringbilan 1 ga qaytaring yoki cheklang (Math.max/min).
β¬ οΈ Oldingi: 23 β Bildirishnoma va sensorlar Β· π Kitob boshi Β· Keyingi: 25 β Autentifikatsiya β‘οΈ