O'lchamlar — useWindowDimensions, foizlar, turli ekranlar

~12 daq · React Native · Stil va layout

Muammodan boshlaylik

Ilova sizning telefoningizda chiroyli. Do'stingizning kichik Android telefonida esa tugmalar ekrandan chiqib ketgan. Planshetda — hamma narsa ulkan, ekranning yarmi bo'sh. Telefonni yonboshlab burishganda — layout buzildi.

Ekranlar 320 dan 1000+ birlik kenglikkacha. Ilova hammasida yaxshi ko'rinishi kerak.


Qattiq raqamlardan qoching

// ❌ 400 kenglikdagi telefonda ishlaydi, 360 da — chiqib ketadi
<View style={{ width: 380 }} />

// ✅ Moslashuvchan
<View style={{ width: '100%' }} />
<View style={{ flex: 1 }} />
<View style={{ alignSelf: 'stretch', marginHorizontal: 16 }} />

Qoida: konteyner kengliklari — flex, foizlar va padding. Qattiq raqamlar — faqat kichik elementlar uchun (ikonka, avatar, tugma balandligi).


useWindowDimensions — ekran o'lchami

import { useWindowDimensions } from 'react-native';

export default function Ekran() {
  const { width, height, fontScale } = useWindowDimensions();
  // width — 390, height — 844 (masalan)
}

Hook — ekran burilganda yoki oyna o'lchami o'zgarganda (planshetda split-screen) avtomatik yangilanadi va komponent qayta chiziladi.

[!INFO] Eski kodda Dimensions.get('window') ni ko'rasiz. U faqat bir marta o'qiladi va burilishni sezmaydi. Komponent ichida doim useWindowDimensions ishlating.

Kenglikka moslashgan grid

const { width } = useWindowDimensions();
const ustunlar = width >= 768 ? 4 : width >= 500 ? 3 : 2;
const bo_shliq = 12;
const kartaKengligi = (width - 16 * 2 - bo_shliq * (ustunlar - 1)) / ustunlar;

Telefonda — 2 ustun, katta telefonda yonboshlab — 3, planshetda — 4.

Karusel — ekran kengligida

const { width } = useWindowDimensions();

<ScrollView horizontal pagingEnabled>
  {bannerlar.map((b) => (
    <Image key={b.id} source={{ uri: b.rasm }} style={{ width, height: width * 0.5 }} />
  ))}
</ScrollView>

Banner balandligi — kenglikning yarmi: har qanday ekranda nisbat saqlanadi. Bu ham aspectRatio: 2 bilan qilish mumkin (7-dars).


Planshetlar

const { width } = useWindowDimensions();
const planshet = width >= 768;

<View style={{ flex: 1, flexDirection: planshet ? 'row' : 'column' }}>
  <View style={{ flex: planshet ? 1 : undefined }}>
    <RoyxatEkran />
  </View>
  {planshet && (
    <View style={{ flex: 2 }}>
      <TafsilotEkran />
    </View>
  )}
</View>

Telefonda — ro'yxat, bosilganda tafsilot alohida ekranda. Planshetda — ro'yxat chapda, tafsilot o'ngda (master-detail).

Juda keng ekranda kontentni cheklash

<View style={{ flex: 1, alignItems: 'center' }}>
  <View style={{ width: '100%', maxWidth: 600, padding: 16 }}>
    {/* forma */}
  </View>
</View>

Planshetda forma 1000 birlik kenglikka cho'zilmaydi.


Ekran yo'nalishi

app.json da:

"orientation": "portrait"
Qiymat Ma'nosi
portrait Faqat tik (ko'pchilik ilovalar)
landscape Faqat yotiq (o'yinlar, video)
default Ikkalasi ham

Ko'p ilovalar portrait bilan cheklanadi — bu qonuniy va oddiy tanlov. Planshet uchun alohida ilova bo'lsa — default va moslashuvchan layout.


Shrift o'lchami — foydalanuvchi sozlamasi

Ko'p foydalanuvchilar (ayniqsa yoshi kattalar) tizim sozlamalarida shriftni kattalashtiradi. React Native Text ni avtomatik kattalashtiradi — bu yaxshi. Lekin dizayn buzilishi mumkin:

// Matnning maksimal kattalashuvini cheklash (butunlay o'chirmang!)
<Text maxFontSizeMultiplier={1.5}>Tugma matni</Text>
const { fontScale } = useWindowDimensions();   // 1 — standart, 1.3 — kattalashtirilgan

Sinab ko'ring: telefon sozlamalarida eng katta shriftni yoqing va ilovani tekshiring. Tugmalarga qattiq height emas, paddingVertical + minHeight bering — matn kattalashganda tugma ham o'ssin.

[!WARNING] allowFontScaling={false} bilan kattalashuvni butunlay o'chirish — ko'rish qobiliyati past foydalanuvchilarga nisbatan adolatsiz va do'konlar ko'rib chiqishida ham salbiy. Cheklang (maxFontSizeMultiplier), lekin o'chirmang.


PixelRatio — chegaralar va rasmlar

import { PixelRatio, StyleSheet } from 'react-native';

PixelRatio.get();                  // 3 — iPhone, 2.625 — ko'p Android
StyleSheet.hairlineWidth;          // eng ingichka chiziq: 1 / PixelRatio
<View style={{ borderBottomWidth: StyleSheet.hairlineWidth, borderColor: '#e2e8f0' }} />

Ro'yxat bandlari orasidagi nozik ajratuvchi chiziq — iOS ilovalaridagidek.


Turli ekranlarda sinash

  • Kichik ekran: Android emulyatorda "Pixel 4a" yoki 5 dyuymli qurilma
  • Katta ekran va planshet: "Pixel Tablet", iPad simulator
  • Yotiq holat: emulyatorni burish
  • Katta shrift: tizim sozlamalari
  • Expo Go dan veb versiyasini ochib (w), brauzer oynasi o'lchamini o'zgartirish — tez tekshiruv

Nima uchun shunday?

Nima uchun React Native da CSS media query lar yo'q?

Media query — statik qoida: "shu kenglikdan katta bo'lsa, shu stil". React Native da esa layout JavaScript da hisoblanadi, va useWindowDimensions sizga o'lchamni oddiy o'zgaruvchi sifatida beradi. Bu media query dan kuchliroq: o'lchamga qarab nafaqat stilni, balki komponentlarni ham almashtirish mumkin (planshetda master-detail, telefonda alohida ekranlar). Shart — oddiy if.


Xulosa

Eslab qoling:

  • Konteynerlar — flex, %, padding; qattiq raqamlar — faqat kichik elementlar uchun
  • useWindowDimensions() — burilish va o'lcham o'zgarishida yangilanadi; Dimensions.get emas
  • Kenglikka qarab ustunlar soni va layout (telefon / planshet)
  • maxWidth — keng ekranda kontentni cheklash
  • orientation — app.json da
  • Foydalanuvchi shrift o'lchami: maxFontSizeMultiplier, tugmalarga minHeight
  • StyleSheet.hairlineWidth — nozik chiziq

Keyingi dars

16-dars: Platform — Android va iOS farqlari, soyalar