логотип PurpleSchool
логотип PurpleSchool

Адаптация safe area context на React Native

Автор

Олег Марков

Введение

Современные мобильные устройства отличаются многообразием размеров экранов, форм-факторов и особенностей конструкции — например, вырезы (notches), скругленные углы, габаритные панели навигации. С появлением iPhone X и подобных моделей новой волны на рынке возникла задача учета так называемой "безопасной области" (safe area) — части экрана, где контент отображается без искажения и вне перекрытия компонентами системы.

В React Native концепция safe area стала особенно актуальна, так как фреймворк ориентирован на кроссплатформенную разработку. Чтобы учесть safe area и избежать перекрытия важных элементов интерфейса, React Native предлагает использовать отдельную библиотеку — react-native-safe-area-context. Давайте разберемся, как интегрировать её в проект, какие возможности она предлагает и на какие нюансы стоит обратить внимание.

Особенности safe area в мобильных интерфейсах

Что такое safe area и зачем она нужна

Safe area — это динамическая зона экрана, находящаяся вне области, перекрываемой такими элементами, как вырезы под камеры и динамики, закругленные углы или панели системной навигации. На iOS safe area впервые появилась в iPhone X, где привычный "статус-бар" приобрел вырез, а нижний край заняла "домашняя" панель навигации. На Android подобные зоны ограничивают отображение контента из-за аппаратных кнопок или выдвижных панелей.

Учет safe area позволяет:

  • Избежать перекрытия важных элементов (кнопок, заголовков) системными интерфейсами устройства.
  • Достичь единообразия в отображении на разных моделях и системах.
  • Гарантировать корректный user experience независимо от особенностей экрана.

Как работает safe area context в React Native

Safe Area Context для React Native — это внешний слой (container) или контекст (provider), информирующий дочерние компоненты о размерах безопасной области экрана. Библиотека react-native-safe-area-context предоставляет инструменты для:

  • Получения значения отступов safe area (padding сверху, снизу, слева, справа).
  • Инкапсуляции оформления внутренних компонентов с автоматическим учетом safe area.
  • Гибкой работы с этим контекстом в любой части дерева компонентов.

Safe area context - это важный инструмент для адаптации пользовательского интерфейса к различным экранам и устройствам, особенно на iOS, где есть вырезы и другие элементы, которые могут перекрывать контент. Правильное использование safe area context позволяет создавать приложения, которые выглядят хорошо на всех устройствах. Если вы хотите детально разобраться в адаптации safe area context на React Native и создавать адаптивные интерфейсы — приходите на наш большой курс React Native и Expo Router. На курсе 184 уроков и 11 упражнений, AI-тренажеры для безлимитной практики с кодом и задачами 24/7, решение задач с живым ревью наставника, еженедельные встречи с менторами.

Установка и базовая интеграция safe area context

Первый шаг — подключение библиотеки к вашему проекту. Ниже инструкция, как это можно сделать независимо от используемого способа интеграции зависимостей.

npm install react-native-safe-area-context
# или если вы используете yarn
yarn add react-native-safe-area-context

Для Expo-проектов

Expo Managed Workflow уже включает эту библиотеку по умолчанию. Если вы используете bare-workflow или ejected проект, также выполните команду выше.

Для Android и iOS

Если ваш проект — bare React Native, выполните:

npx pod-install

или перейдите в ios и выполните pod install вручную, чтобы подключить нативные зависимости для iOS.

Этот шаг нужен только для iOS, так как Android подключает зависимости автоматически.

Использование SafeAreaProvider на верхнем уровне приложения

Чтобы все ваши компоненты могли узнать размеры safe area, поместите их внутрь SafeAreaProvider. Обычно его добавляют сразу внутри root-компонента приложения, например, в App.js:

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

export default function App() {
  return (
    <SafeAreaProvider>
      {/* Ваши навигация и компоненты */}
    </SafeAreaProvider>
  );
}

SafeAreaProvider отслеживает смену safe area, подстраиваясь под состояние экрана, ориентацию, вырезы и даже появления/скрытия виртуальных клавиатур.

Получение safe area через хук useSafeAreaInsets

Хук useSafeAreaInsets — основной способ "подсмотреть" актуальные отступы safe area, чтобы подстроить стили конкретного элемента.

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

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

  return (
    <View style={{
      paddingTop: insets.top,
      paddingBottom: 16,
      backgroundColor: '#eaeaea',
    }}>
      {/* Ваш контент */}
    </View>
  );
}

Вот что здесь происходит:

  • insets.top сообщает, сколько пикселей нужно отступить сверху от опасной зоны (например, для iOS это может быть 44px на iPhone X).
  • Таким образом, компонент не "прячется" под вырезами и статус-баром.
  • Вы также можете использовать insets.bottom, insets.left, insets.right для аналогичных целей.

SafeAreaView — автоматическое добавление safe area

Если вы хотите, чтобы компонент уже учитывал safe area, используйте готовый компонент SafeAreaView:

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

function ScreenLayout({ children }) {
  return (
    <SafeAreaView style={{ flex: 1, backgroundColor: 'white' }}>
      {children}
    </SafeAreaView>
  );
}

Важные опции SafeAreaView:

  • edges — указывает, для каких сторон safe area нужно учитывать (по умолчанию [top, right, bottom, left]):
<SafeAreaView
  edges={['top', 'left']}
  style={{ flex: 1 }}>
  {/* Контент не будет перекрываться только сверху и слева */}
</SafeAreaView>
  • mode — режим учета safe area (например, padding или margin):
<SafeAreaView mode="margin" style={{ flex: 1 }}>
  {/* Safe area учитывается через отступы margin */}
</SafeAreaView>

Практические случаи использования safe area

Отступы для шторки и панели навигации

Рассмотрим пример, где заголовок приложения не должен перекрываться ни статус-баром, ни вырезом:

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

  return (
    <View style={{
      paddingTop: insets.top + 12, // дополнительный отступ по желанию
      paddingHorizontal: 16,
      height: 56 + insets.top,
      backgroundColor: '#24292e',
      justifyContent: 'center',
    }}>
      <Text style={{ color: 'white', fontWeight: 'bold' }}>Заголовок</Text>
    </View>
  );
}

Такой подход особенно удобен при создании кастомных баров, когда вы не хотите использовать стандартные компоненты навигации.

Футер с учетом safe area (например, для кнопок)

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

  return (
    <View style={{
      paddingBottom: insets.bottom + 16, // учитываем safe area
      alignItems: 'center',
    }}>
      <Button title="Продолжить" onPress={...} />
    </View>
  );
}

Теперь кнопка никогда не уедет за пределы экрана даже на устройствах с большими панелями или вырезами снизу.

Различия между iOS и Android

Особенности safe area на iOS

  • У iOS safe area всегда динамический — она зависит от текущего положения устройства и ориентации экрана.
  • Например, на iPhone с Face ID при альбомной ориентации safe area изменяется, чтобы не "залезать" на боковые грани.
  • Отступы могут быть разными даже у одного и того же устройства в разных положениях.

Что насчет Android

  • До версии Android P официального safe area не было — но вырезы и закругления появились позже.
  • Библиотека react-native-safe-area-context обрабатывает это на уровне нативного кода, подтягивая значенияInsets.
  • Некоторые старые или кастомные прошивки могут отдавать неверные значения insets — об этом стоит помнить и тестировать приложение на максимально широком парке устройств.

Эмуляция safe area в эмуляторах и симуляторах

Порой удобно проверить, как ведет себя ваше приложение в ситуациях, когда safe area необычен:

  • В XCode Simulator можно выбрать устройства с вырезами (iPhone X и новее).
  • Для Android используйте эмуляторы Pixel 3 и новее.
  • В настройках симулятора можно добавлять закругления, вырезы.

Рекомендую после адаптации всегда проверять приложение на разных моделях, особенно если вы используете кастомные элементы поверх safe area.

Советы по организации кода и структуре компонентов

  • Поместите SafeAreaProvider на верхний уровень, чтобы все дочерние компоненты могли использовать safe area без дополнительных оберток.
  • Для экранов используйте SafeAreaView, чтобы контейнер сразу учитывал safe area.
  • Для отдельных элементов (хедер, футер) используйте useSafeAreaInsets для большей гибкости.
  • Подумайте, когда применять padding, а когда margin, чтобы оформление было логичным и не "сползало" при изменении ориентации или размера.
  • Разделяйте логику safe area и основной стиль через отдельные стили, чтобы код проще модифицировался.

Ошибки и трудности, с которыми сталкиваются разработчики

  • Отсутствие SafeAreaProvider. Если не обернуть приложение в SafeAreaProvider, хук вернет нули, а SafeAreaView не даст результата.
  • Дублирование SafeAreaView и padding. Неправильно применять и SafeAreaView, и ручные padding — это удваивает отступы!
  • Ошибки в edges. Если забыть указать нужную грань в edges, компонент опять может попасть под вырез.
  • Стилизация через margin, когда нужен padding. В зависимости от структуры это может приводить к перекрытию фона или, наоборот, к отступам, которые кажутся избыточными.

Сценарии расширенного использования

Использование SafeAreaInsetsContext

Иногда удобно передавать значения insets глубоко вниз по дереву компонентов через контекст.

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

function DeepNestedComponent() {
  return (
    <SafeAreaInsetsContext.Consumer>
      {insets => (
        <View style={{ marginTop: insets.top }}>
          {/* Ваш глубокий UI */}
        </View>
      )}
    </SafeAreaInsetsContext.Consumer>
  );
}

Такой способ актуален, если по каким-то причинам нельзя использовать хук (например, в классических компонентах).

Совместное использование со сторонними библиотеками

  • Многие навигационные библиотеки (например, React Navigation) уже используют SafeAreaProvider. Проверьте документацию вашего роутера, чтобы избежать вложения провайдеров.
  • При использовании модальных окон или popover-компонентов отступы safe area могут вести себя иначе — проверяйте отображение на нескольких устройствах.

Взаимодействие с KeyboardAvoidingView

Если ваше приложение активное по введению текста и содержит KeyboardAvoidingView, важно правильно комбинировать safe area и отступы клавиатуры:

<SafeAreaView style={{ flex: 1 }}>
  <KeyboardAvoidingView
    style={{ flex: 1 }}
    behavior={Platform.OS === 'ios' ? 'padding' : null}>
    {/* Контент */}
  </KeyboardAvoidingView>
</SafeAreaView>

Так элементы не "уедут" под клавиатуру или вырез

Заключение

В React Native грамотная работа с safe area существенно повышает качество приложения, обеспечивая адекватное и предсказуемое отображение контента на устройствах разных форм-факторов и платформ. Используйте SafeAreaProvider для установки контекста safe area, SafeAreaView или хук useSafeAreaInsets для простого доступа к отступам. Проверяйте результат на разных устройствах и в разных ориентациях, чтобы не столкнуться с неожиданными артефактами в интерфейсе. Гибкий, современный подход к вёрстке с учетм safe area становится неотъемлемой частью дружелюбных и профессиональных мобильных интерфейсов.

Адаптация safe area context - это важный, но не единственный аспект разработки качественного React Native приложения. Для создания полноценного приложения необходимо освоить множество других технологий и подходов, включая работу с UI, данными и нативными функциями. Курс React Native и Expo Router поможет вам в этом. В первых 3 модулях уже доступно бесплатное содержание — начните погружаться в мир React Native прямо сегодня.

Частозадаваемые технические вопросы по теме

Как получить safe area insets внутри классового компонента?

Используйте SafeAreaInsetsContext.Consumer — добавьте в JSX вашего компонента:

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

class MyComponent extends React.Component {
  render() {
    return (
      <SafeAreaInsetsContext.Consumer>
        {insets => (
          <View style={{ paddingTop: insets.top }}>
            {/* Ваш контент */}
          </View>
        )}
      </SafeAreaInsetsContext.Consumer>
    );
  }
}

Почему SafeAreaView не работает или все отступы равны нулю?

Чаще всего причина — отсутствие SafeAreaProvider на верхнем уровне или неправильный порядок вложенности. Проверьте, что ваше приложение обернуто в SafeAreaProvider.

Как корректно использовать SafeAreaView вместе с ScrollView?

Оборачивайте ScrollView внутри SafeAreaView:

<SafeAreaView style={{ flex: 1 }}>
  <ScrollView>
    {/* Контент */}
  </ScrollView>
</SafeAreaView>

Или учитывайте insets через хук для кастомных случаев прокрутки.

Как отключить safe area для определенного компонента?

SafeAreaView позволяет указать свойство edges. Просто задайте те стороны, для которых хотите safe area, остальные — отключатся:

<SafeAreaView edges={['left', 'right']} style={{ flex: 1 }}>
  {/* Safe area только слева и справа */}
</SafeAreaView>

Safe Area не обновляется при изменении ориентации экрана — что делать?

Убедитесь, что используется последняя версия библиотеки и SafeAreaProvider находится в корне приложения. Safe area должна пересчитываться автоматически, но в специфичных случаях для нестандартных Android-устройств может потребоваться дополнительное тестирование, а также обновление зависимости.

Стрелочка влевоОптимизация переходов между экранами в React NativeОбзор библиотек для навигации в React NativeСтрелочка вправо

Постройте личный план изучения React-native до уровня Middle — бесплатно!

React-native — часть карты развития Mobile

  • step100+ шагов развития
  • lessons30 бесплатных лекций
  • lessons300 бонусных рублей на счет

Бесплатные лекции

Все гайды по React-native

Работа со ScrollView в React NativeРабота с видео в React NativeКак реализовать аудиоплеер на React NativeНастройка и использование input и textinput в React NativeИнтеграция видео плеера в приложение на React NativeИспользование выпадающих списков в React NativeСоздание и настройка native module на React NativeКак создать модальные окна в React NativeРабота с изображениями в React NativeОтображение списков данных в React NativeГайд по файловой системе в React NativeИнтеграция камеры в приложение на React NativeСоздание интерактивных кнопок в React Native
Как использовать векторные иконки в React Native5 популярных библиотек UI компонентов React NativeСоздание и использование tabs в React NativeРуководство по стилизации компонентов в React NativeОптимизация переходов между экранами в React NativeАдаптация safe area context на React NativeОбзор библиотек для навигации в React NativeСоздание сложных анимаций (reanimated) на React NativeИспользование библиотеки стилей Paper в React NativeРуководство по navigation в React NativeОптимизация отображения списков в React NativeКак реализовать linking на React NativeГайд по UI-китам для React NativeГде искать elements для приложения на React NativeРабота с цветами в React Native
Открыть базу знаний

Лучшие курсы по теме

изображение курса

React Native и Expo Router

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Основы JavaScript

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.8
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

TypeScript с нуля

Антон Ларичев
AI-тренажеры
Практика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее

Отправить комментарий