Drawer va modal ekranlar

~12 daq · React Native · Navigatsiya — Expo Router

Muammodan boshlaylik

Ikki vazifa:

  1. Admin panel ilovasi — 9 ta bo'lim. Tab panelga sig'maydi (5 tadan ko'p — 27-dars)
  2. "Filtr" yoki "Yangi manzil qo'shish" — joriy ishni to'xtatmasdan, ustida ochiladigan ekran. Tugatgach — yopiladi va foydalanuvchi aynan qolgan joyiga qaytadi

Birinchisi — drawer (yon menyu). Ikkinchisi — modal ekran.


Modal ekranlar

11-darsda Modal komponentini ko'rdik. Expo Router da yaxshiroq yo'l bor — modalni alohida ekran sifatida ochish:

app/
├── _layout.tsx
├── (tabs)/...
└── filtr.tsx            ← modal sifatida ochiladi
// app/_layout.tsx
<Stack>
  <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
  <Stack.Screen
    name="filtr"
    options={{
      presentation: 'modal',
      title: 'Filtr',
    }}
  />
</Stack>

Ochish — oddiy navigatsiya:

<Link href="/filtr">Filtr</Link>
// yoki
router.push('/filtr');

Yopish:

router.back();
// yoki
router.dismiss();

presentation turlari

Qiymat Ko'rinishi
card Oddiy stack ekran (standart)
modal Pastdan chiqadi; iOS da orqadagi ekran ko'rinib turadigan "varaq"
fullScreenModal Butun ekranni egallaydi
formSheet iOS: kichikroq varaq; balandlikni sozlash mumkin
transparentModal Shaffof fon — o'z dizayningizdagi oyna uchun

Komponent Modal dan afzalligi

  • O'z URL i bor — deep link bilan ochish mumkin (mening-dokon://filtr)
  • Holat va mantiq alohida faylda — asosiy ekran "toza"
  • iOS da pastga tortib yopish, Android "orqaga" — avtomatik
  • Ichida o'z stack i bo'lishi mumkin (ko'p qadamli forma)

Modaldan natija qaytarish

Filtr tanlandi — katalog ekrani buni bilishi kerak. Eng toza yo'l — URL parametrlari (29-dars) yoki umumiy holat (Zustand, 33-dars):

// app/filtr.tsx
function qollash() {
  router.dismissTo({ pathname: '/katalog', params: { minNarx: '100000', toifa: 'telefonlar' } });
}
// app/(tabs)/katalog.tsx
const { minNarx, toifa } = useLocalSearchParams<{ minNarx?: string; toifa?: string }>();

Shaffof modal — o'z dialogingiz

<Stack.Screen name="tasdiqlash" options={{ presentation: 'transparentModal', animation: 'fade', headerShown: false }} />
// app/tasdiqlash.tsx
export default function Tasdiqlash() {
  return (
    <Pressable style={{ flex: 1, backgroundColor: 'rgba(0,0,0,0.5)', justifyContent: 'center', padding: 24 }} onPress={() => router.back()}>
      <Pressable style={{ backgroundColor: 'white', borderRadius: 16, padding: 24, gap: 16 }}>
        <Text style={{ fontSize: 18, fontWeight: '700' }}>Buyurtmani bekor qilasizmi?</Text>
        {/* tugmalar */}
      </Pressable>
    </Pressable>
  );
}

Drawer — yon menyu

npx expo install @react-navigation/drawer react-native-gesture-handler react-native-reanimated
app/
├── _layout.tsx
└── (drawer)/
    ├── _layout.tsx       ← Drawer
    ├── index.tsx         ← Boshqaruv paneli
    ├── buyurtmalar.tsx
    ├── mahsulotlar.tsx
    ├── mijozlar.tsx
    └── sozlamalar.tsx
// app/(drawer)/_layout.tsx
import { Drawer } from 'expo-router/drawer';
import { Ionicons } from '@expo/vector-icons';

export default function DrawerLayout() {
  return (
    <Drawer
      screenOptions={{
        drawerActiveTintColor: '#0284c7',
        drawerActiveBackgroundColor: '#e0f2fe',
        drawerLabelStyle: { marginLeft: -8 },
      }}
    >
      <Drawer.Screen
        name="index"
        options={{
          title: 'Boshqaruv paneli',
          drawerIcon: ({ color, size }) => <Ionicons name="speedometer-outline" size={size} color={color} />,
        }}
      />
      <Drawer.Screen
        name="buyurtmalar"
        options={{
          title: 'Buyurtmalar',
          drawerIcon: ({ color, size }) => <Ionicons name="receipt-outline" size={size} color={color} />,
        }}
      />
      {/* ... */}
    </Drawer>
  );
}

Drawer avtomatik:

  • Sarlavhada "☰" tugmasi
  • Ekranning chap chetidan surib ochish
  • Faol bo'limni belgilash

Kodda ochish:

import { useNavigation } from 'expo-router';
import { DrawerActions } from '@react-navigation/native';

const navigation = useNavigation();
navigation.dispatch(DrawerActions.openDrawer());

O'z menyu dizayni

import { DrawerContentScrollView, DrawerItemList } from '@react-navigation/drawer';

<Drawer
  drawerContent={(props) => (
    <DrawerContentScrollView {...props}>
      <View style={{ padding: 16, alignItems: 'center', gap: 8 }}>
        <Avatar ism="Admin" olcham={64} />
        <Text style={{ fontWeight: '700' }}>Admin</Text>
      </View>
      <DrawerItemList {...props} />
      <Pressable onPress={chiqish} style={{ padding: 16 }}>
        <Text style={{ color: '#dc2626' }}>Chiqish</Text>
      </Pressable>
    </DrawerContentScrollView>
  )}
>

Tepada profil, o'rtada bandlar, pastda "Chiqish".


Qaysi biri qachon

Holat Tanlov
3–5 asosiy bo'lim, tez-tez almashtiriladi Tabs
Ko'p bo'lim, kam almashtiriladi (admin, sozlamalar) Drawer
Joriy ishni to'xtatmaydigan qisqa vazifa (filtr, tanlash, forma) Modal
Ketma-ket chuqurlashish (katalog → mahsulot → sharh) Stack

Ko'pincha birga: ildiz Stack → ichida Tabs → har bir tab ichida Stack, ustida modallar.

[!INFO] Drawer zamonaviy iste'molchi ilovalarida kamroq ishlatiladi: undagi bandlar "yashirin" — foydalanuvchi ularni kam topadi. Asosiy bo'limlar uchun tablar afzal; drawer — ichki, professional ilovalar uchun.


Nima uchun shunday?

Nima uchun modalni komponent emas, alohida ekran qilish yaxshiroq?

Chunki modal ko'pincha mustaqil vazifa: o'z ma'lumot yuklashi, formasi, validatsiyasi va hatto ichki qadamlari bor. Uni asosiy ekran ichida useState va Modal bilan saqlash — asosiy ekranni shishirib yuboradi va modalni boshqa joydan ochishni qiyinlashtiradi. Alohida ekran sifatida modal — o'z fayli, o'z URL i, tizim imo-ishoralari bilan; uni ilovaning istalgan joyidan bitta router.push bilan ochish mumkin.


Xulosa

Eslab qoling:

  • Modal ekran: alohida fayl + presentation: 'modal'; ochish — push, yopish — back / dismiss
  • presentation: modal, fullScreenModal, formSheet, transparentModal
  • Natija qaytarish — URL parametrlari yoki umumiy holat
  • Drawer: expo-router/drawer, drawerIcon, chapdan surish, drawerContent — o'z dizayni
  • Tabs — asosiy bo'limlar; Drawer — ko'p, kam ishlatiladigan bo'limlar; Modal — qisqa vazifa; Stack — chuqurlashish

Keyingi dars

29-dars: Dinamik yo'llar va parametrlar — [id].tsx, deep link