Tablar — pastki panel, ikonkalar, badge
Muammodan boshlaylik
Do'kon ilovasining asosiy bo'limlari: Bosh sahifa, Katalog, Savat, Profil. Foydalanuvchi ular orasida tez-tez o'tadi — va har biri o'z holatini saqlashi kerak: katalogdagi scroll, savatdagi mahsulotlar.
Deyarli har bir mobil ilovada — ekran pastida tab panel. Instagram, Telegram, Uzum Market — hammasida.
Tuzilma
app/
├── _layout.tsx ← Stack (ildiz)
├── (tabs)/
│ ├── _layout.tsx ← Tabs
│ ├── index.tsx ← Bosh
│ ├── katalog.tsx
│ ├── savat.tsx
│ └── profil.tsx
└── mahsulot/[id].tsx ← tablar ustida, Stack da
// app/_layout.tsx
import { Stack } from 'expo-router';
export default function RootLayout() {
return (
<Stack>
<Stack.Screen name="(tabs)" options={{ headerShown: false }} />
<Stack.Screen name="mahsulot/[id]" options={{ title: 'Mahsulot' }} />
</Stack>
);
}
(tabs) ning o'z sarlavhasi bor (Tabs dagi), shuning uchun Stack sarlavhasi yashiriladi — aks holda ikki qavat sarlavha chiqadi.
Tabs layout
// app/(tabs)/_layout.tsx
import { Tabs } from 'expo-router';
import { Ionicons } from '@expo/vector-icons';
export default function TabLayout() {
return (
<Tabs
screenOptions={{
tabBarActiveTintColor: '#0284c7',
tabBarInactiveTintColor: '#94a3b8',
tabBarLabelStyle: { fontSize: 11, fontWeight: '600' },
}}
>
<Tabs.Screen
name="index"
options={{
title: 'Bosh',
tabBarIcon: ({ color, size, focused }) => (
<Ionicons name={focused ? 'home' : 'home-outline'} size={size} color={color} />
),
}}
/>
<Tabs.Screen
name="katalog"
options={{
title: 'Katalog',
tabBarIcon: ({ color, size, focused }) => (
<Ionicons name={focused ? 'grid' : 'grid-outline'} size={size} color={color} />
),
}}
/>
<Tabs.Screen
name="savat"
options={{
title: 'Savat',
tabBarIcon: ({ color, size, focused }) => (
<Ionicons name={focused ? 'cart' : 'cart-outline'} size={size} color={color} />
),
}}
/>
<Tabs.Screen
name="profil"
options={{
title: 'Profil',
tabBarIcon: ({ color, size, focused }) => (
<Ionicons name={focused ? 'person' : 'person-outline'} size={size} color={color} />
),
}}
/>
</Tabs>
);
}
tabBarIcon— funksiya:color(faol/nofaol rang),size,focused- Faol tab — to'ldirilgan ikonka, nofaol — chiziqli. iOS va Android dizayn tavsiyasi
- Tablar tartibi —
Tabs.Screenlar tartibida - Tab panel safe area ni (pastki indikator) o'zi hisobga oladi (18-dars)
Badge — savatdagi son
const soni = useSavat((s) => s.mahsulotlar.length); // Zustand, 33-dars
<Tabs.Screen
name="savat"
options={{
title: 'Savat',
tabBarBadge: soni > 0 ? soni : undefined,
tabBarBadgeStyle: { backgroundColor: '#dc2626', fontSize: 10 },
tabBarIcon: ...,
}}
/>
undefined — badge ko'rinmaydi. 0 yozsangiz — "0" ko'rinadi.
Tab ichida stack
Katalog → toifa → mahsulot: tab panel ko'rinib turishi kerakmi?
Variant 1 — tablar ustida (yuqoridagi tuzilma). Mahsulot ekrani ildiz Stack da — u tablarni yopib ochiladi. Diqqat mahsulotga qaratiladi. Ko'p do'kon ilovalari shunday.
Variant 2 — tab ichida. Har bir tab o'z stack iga ega, tab panel doim ko'rinadi:
app/(tabs)/
├── _layout.tsx
├── katalog/
│ ├── _layout.tsx ← Stack
│ ├── index.tsx ← /katalog
│ └── [toifa].tsx ← /katalog/telefonlar
└── profil.tsx
// app/(tabs)/katalog/_layout.tsx
import { Stack } from 'expo-router';
export default function KatalogStack() {
return <Stack />;
}
// app/(tabs)/_layout.tsx
<Tabs.Screen name="katalog" options={{ headerShown: false, title: 'Katalog', tabBarIcon: ... }} />
headerShown: false — Tabs sarlavhasini yashirish, chunki ichki Stack o'z sarlavhasini ko'rsatadi.
Har bir tab o'z stack ini eslab qoladi: katalogda 3 ekran chuqur kirdingiz, profilga o'tib, qaytdingiz — yana o'sha 3-ekrandasiz. Instagram aynan shunday.
Tab bosish hodisalari
Faol tabni qayta bosganda — ro'yxat tepasiga qaytish (Instagram, Telegram):
import { useScrollToTop } from '@react-navigation/native';
export default function Katalog() {
const ref = useRef<FlatList>(null);
useScrollToTop(ref);
return <FlatList ref={ref} ... />;
}
Bitta qator — va tab ikkinchi marta bosilganda avtomatik tepaga.
Tabni bosishni ushlash (masalan, "+" tabi ekran emas, modal ochishi kerak):
<Tabs.Screen
name="yangi"
options={{ title: '', tabBarIcon: () => <Ionicons name="add-circle" size={36} color="#0284c7" /> }}
listeners={{
tabPress: (e) => {
e.preventDefault(); // tabga o'tmaslik
router.push('/yangi-elon'); // modal ochish
},
}}
/>
Tabni yashirish
<Tabs.Screen name="maxfiy" options={{ href: null }} />
href: null — fayl (tabs)/ da, lekin tab panelda ko'rinmaydi.
Dizayn maslahatlari
- 3–5 ta tab. Ko'proq bo'lsa — "Yana" tabi yoki drawer
- Har bir tab — mustaqil, muhim bo'lim. "Sozlamalar" odatda tab emas — profil ichida
- Ikonka va matn — faqat ikonka tushunarsiz bo'lishi mumkin
- Tab paneli har doim bir xil. Ekranga qarab tablarni almashtirish — chalkashtiradi
Nima uchun shunday?
Nima uchun tab panel mobil ilovalarda pastda, vebda esa navigatsiya tepada?
Ergonomika. Telefonni bir qo'lda ushlaganda bosh barmoq ekranning pastki qismiga oson yetadi, yuqori burchaklarga esa yetmaydi. Katta ekranli zamonaviy telefonlarda bu yanada muhim. Shuning uchun eng ko'p ishlatiladigan amallar — pastda. Veb esa sichqoncha va katta ekran uchun loyihalangan — u yerda "qo'l yetishi" muammo emas.
Xulosa
Eslab qoling:
(tabs)/_layout.tsxda<Tabs>; ildiz Stack da(tabs)sarlavhasi yashiriladitabBarIcon: ({ color, size, focused })— faol: to'ldirilgan, nofaol: chiziqlitabBarBadge— son;undefined— yashirish- Tablar ustida (ildiz Stack) yoki tab ichida (ichki Stack) — dizayn qarori
useScrollToTop(ref)— tabni qayta bosganda tepagalisteners.tabPress+preventDefault— tabni maxsus amalga aylantirishhref: null— tabni yashirish; 3–5 tab
Keyingi dars
28-dars: Drawer va modal ekranlar