Qorong'i rejim — useColorScheme, mavzu tizimi

~15 daq · React Native · Stil va layout

Muammodan boshlaylik

Foydalanuvchi kechqurun telefonida qorong'i rejimni yoqdi. Barcha ilovalar qorong'i — sizning ilovangizdan tashqari. Qop-qora xonada oppoq ekran ko'zni qamashtiradi. Yoki yanada yomon: ba'zi tizim elementlari qorong'i bo'ldi, sizning oq fondagi qora matningiz esa qora fondagi qora matnga aylandi.

Bugun qorong'i rejim — "qo'shimcha imkoniyat" emas, kutilgan standart.


1. app.json da yoqish

{
  "expo": {
    "userInterfaceStyle": "automatic"
  }
}
Qiymat Ma'nosi
automatic Tizim sozlamasiga qarab (tavsiya)
light Doim yorug'
dark Doim qorong'i

light bo'lsa — useColorScheme doim 'light' qaytaradi.


2. useColorScheme

import { useColorScheme } from 'react-native';

export default function Ekran() {
  const sxema = useColorScheme();   // 'light' | 'dark' | null
  const qorongi = sxema === 'dark';

  return (
    <View style={{ flex: 1, backgroundColor: qorongi ? '#0f172a' : '#ffffff' }}>
      <Text style={{ color: qorongi ? '#f1f5f9' : '#0f172a' }}>Salom</Text>
    </View>
  );
}

Foydalanuvchi tizim sozlamasini o'zgartirsa — hook avtomatik yangilanadi va ekran darhol qayta chiziladi.

Lekin har bir komponentda qorongi ? ... : ... yozish — tez orada tartibsizlikka aylanadi. Kerak — mavzu tizimi.


3. Mavzu tizimi

Ranglarni ma'nosi bo'yicha nomlang

// constants/theme.ts
export const mavzular = {
  light: {
    fon: '#ffffff',
    fonIkkinchi: '#f8fafc',
    karta: '#ffffff',
    matn: '#0f172a',
    matnIkkinchi: '#64748b',
    chegara: '#e2e8f0',
    asosiy: '#0284c7',
    asosiyMatn: '#ffffff',
    xato: '#dc2626',
  },
  dark: {
    fon: '#0b1120',
    fonIkkinchi: '#0f172a',
    karta: '#1e293b',
    matn: '#f1f5f9',
    matnIkkinchi: '#94a3b8',
    chegara: '#334155',
    asosiy: '#38bdf8',
    asosiyMatn: '#0b1120',
    xato: '#f87171',
  },
} as const;

export type Mavzu = typeof mavzular.light;

oq, qora emas — fon, matn, karta. Komponent "bu yerga matn rangi" deydi, u qaysi rang ekanini mavzu hal qiladi.

Custom hook

// hooks/useMavzu.ts
import { useColorScheme } from 'react-native';
import { mavzular } from '@/constants/theme';

export function useMavzu() {
  const sxema = useColorScheme() ?? 'light';
  return mavzular[sxema];
}

Ishlatish

import { useMavzu } from '@/hooks/useMavzu';

export function MahsulotKarta({ nom, narx }: { nom: string; narx: number }) {
  const m = useMavzu();

  return (
    <View style={[styles.karta, { backgroundColor: m.karta, borderColor: m.chegara }]}>
      <Text style={[styles.nom, { color: m.matn }]}>{nom}</Text>
      <Text style={{ color: m.matnIkkinchi }}>{narx.toLocaleString()} so'm</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  karta: { padding: 16, borderRadius: 12, borderWidth: 1 },   // rangsiz tuzilma
  nom: { fontSize: 16, fontWeight: '600' },
});

Naqsh: StyleSheet da — tuzilma (o'lcham, padding, radius), massivning ikkinchi qismida — mavzu ranglari.

Stillarni hook ichida yaratish

Rang ko'p bo'lsa, bu usul tozaroq:

function useStillar() {
  const m = useMavzu();
  return useMemo(() => StyleSheet.create({
    ekran: { flex: 1, backgroundColor: m.fon },
    sarlavha: { fontSize: 22, fontWeight: '700', color: m.matn },
    izoh: { color: m.matnIkkinchi },
  }), [m]);
}

export default function Ekran() {
  const s = useStillar();
  return <View style={s.ekran}><Text style={s.sarlavha}>Salom</Text></View>;
}

useMemo — stillar faqat mavzu o'zgarganda qayta yaratiladi.


4. Navigatsiya va status bar

Expo Router sarlavhalari va tab panellari ham mavzuga mos bo'lishi kerak:

// app/_layout.tsx
import { ThemeProvider, DarkTheme, DefaultTheme } from '@react-navigation/native';
import { StatusBar } from 'expo-status-bar';
import { useColorScheme } from 'react-native';

export default function RootLayout() {
  const sxema = useColorScheme();
  return (
    <ThemeProvider value={sxema === 'dark' ? DarkTheme : DefaultTheme}>
      <Stack />
      <StatusBar style="auto" />
    </ThemeProvider>
  );
}

5. Foydalanuvchi tanlovi

Ko'p ilovalar sozlamalarda "Tizim / Yorug' / Qorong'i" tanlovini beradi:

import { Appearance } from 'react-native';

Appearance.setColorScheme('dark');    // majburan qorong'i
Appearance.setColorScheme('light');
Appearance.setColorScheme(null);      // tizimga qaytish

Tanlovni qurilmada saqlash — AsyncStorage (34-dars) va ilova ochilganda qo'llash.


Dizayn maslahatlari

  • Sof qora emas — #000 o'rniga to'q ko'k-kulrang (#0b1120). Ko'zga yumshoqroq, soyalar va qatlamlar ko'rinadi
  • Qorong'ida chuqurlik — yorqinlik bilan: yuqoridagi qatlam (karta) fondan biroz ochroq. Soyalar qorong'ida deyarli ko'rinmaydi
  • Asosiy rangni biroz ochroq qiling (#0284c7 → #38bdf8) — to'q fonda kontrast yetarli bo'lsin
  • Rasmlar va logotiplar — qorong'i fonda ko'rinishini tekshiring (shaffof PNG dagi qora logo yo'qolib qoladi)
  • Ikkala rejimda ham kontrastni tekshiring — matn va fon orasida kamida 4.5:1

Nima uchun shunday?

Nima uchun ranglarni "oq/qora" emas, "fon/matn" deb nomlash kerak?

Chunki rang — bu rol, qiymat emas. Agar komponentda color: ranglar.qora yozilgan bo'lsa — qorong'i rejimda u "qora" bo'lib qolishi kerakmi yoki "oq" ga aylanishi kerakmi? Noaniq. color: m.matn esa aniq: "asosiy matn rangi" — yorug'da qora, qorong'ida oq. Rollar bo'yicha nomlash dizayn tizimini rejimdan, brenddan va hatto kelajakdagi "yuqori kontrast" rejimidan mustaqil qiladi.


Xulosa

Eslab qoling:

  • app.json: "userInterfaceStyle": "automatic"
  • useColorScheme() — 'light' / 'dark', avtomatik yangilanadi
  • Ranglar — rol bo'yicha: fon, matn, karta, chegara, asosiy
  • useMavzu() hook; StyleSheet da tuzilma, massivda ranglar
  • Navigatsiya — ThemeProvider + DarkTheme; StatusBar style="auto"
  • Appearance.setColorScheme — foydalanuvchi tanlovi
  • Sof qora emas; qorong'ida asosiy rangni ochroq qiling

Keyingi dars

18-dars: Safe area — notch, status bar, pastki panel