Урок 05

Safe Area и адаптивность

Мобильные экраны отличаются: «челка», домашняя кнопка, разные размеры. Нужно адаптироваться.

Safe Area

Safe Area — область экрана, не перекрытая системными элементами.

npx expo install react-native-safe-area-context
import { SafeAreaView } from 'react-native-safe-area-context';

<SafeAreaView style={{ flex: 1 }} edges={['top', 'bottom']}>
    {/* контент */}
</SafeAreaView>

edges:

  • 'top' — сверху (челка, статус-бар)
  • 'bottom' — снизу (домашняя кнопка)
  • 'left', 'right' — по бокам
  • ['top', 'bottom'] — комбинация

useSafeAreaInsets

Для точных отступов:

import { useSafeAreaInsets } from 'react-native-safe-area-context';

function Screen() {
    const insets = useSafeAreaInsets();

    return (
        <View style={{ paddingTop: insets.top, paddingBottom: insets.bottom }}>
            {/* контент */}
        </View>
    );
}

Dimensions

Размеры экрана:

import { Dimensions } from 'react-native';

const { width, height } = Dimensions.get('window');

При повороте экрана — слушать изменения:

import { useWindowDimensions } from 'react-native';

function Screen() {
    const { width, height } = useWindowDimensions();

    return (
        <View style={{ width: width - 32 }}>
            {/* контент */}
        </View>
    );
}

useWindowDimensions — предпочтительно. Обновляется автоматически.

Проценты

<View style={{ width: '50%', height: '100%' }} />

Работает для ширины и высоты, но не для отступов.

Условные стили по ширине

function Screen() {
    const { width } = useWindowDimensions();
    const isTablet = width >= 768;

    return (
        <View style={[styles.container, isTablet && styles.tablet]}>
            {/* контент */}
        </View>
    );
}

PixelRatio

import { PixelRatio } from 'react-native';

PixelRatio.get();          // 2 на iPhone, 3 на Pro
PixelRatio.getFontScale(); // масштаб шрифта пользователя

Не нужно для большинства случаев — React Native сам адаптируется.

Статус-бар

import { StatusBar } from 'expo-status-bar';

<StatusBar style="auto" />
<StatusBar style="light" />
<StatusBar style="dark" />
<StatusBar hidden />

Адаптивность

const { width } = useWindowDimensions();

const cardWidth = width < 375 ? '100%' : '48%';

Или через flexWrap:

<View style={{ flexDirection: 'row', flexWrap: 'wrap', gap: 12 }}>
    {items.map((item) => (
        <View key={item.id} style={{ width: '48%' }}>
            {/* карточка */}
        </View>
    ))}
</View>

Клавиатура и safe area

<SafeAreaView style={{ flex: 1 }}>
    <KeyboardAvoidingView
        behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
        style={{ flex: 1 }}
    >
        {/* форма */}
    </KeyboardAvoidingView>
</SafeAreaView>

Ориентация

В app.json:

{
    "expo": {
        "orientation": "portrait"
    }
}

Варианты: default, portrait, landscape.

Если ты уже знаешь React

В вебе — медиазапросы и vw/vh. В React Native — useWindowDimensions, проценты, SafeAreaView. Нельзя просто написать CSS-медиазапрос.

Итоги

  • SafeAreaView для системных элементов
  • useSafeAreaInsets для точных отступов
  • useWindowDimensions для адаптивности
  • Проценты для ширины
  • app.json для ориентации