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

Работа с изображениями в React Native

Автор

Олег Марков

Введение

Работа с изображениями - один из важных аспектов при разработке мобильных приложений на React Native. Картинки делают интерфейс привлекательнее, помогают наполнить контент, реализовать визуальные сценарии, а иногда вообще являются основным элементом взаимодействия пользователя с приложением.

В этой статье мы разберем все ключевые моменты, связанные с использованием изображений в React Native: как подключать локальные и удаленные изображения, менять их размер, оптимизировать, обрабатывать ошибки загрузки, делать кэширование и добавлять кастомные компоненты для работы с изображениями. Я покажу вам практические примеры кода и обращу внимание на детали, которые помогут избежать распространённых проблем.

Основы использования изображений

Компонент Image

В React Native для вывода изображений используется компонент Image. Он есть во всех проектах по умолчанию, не требует отдельной установки. Давайте посмотрим, как его можно использовать:

import { Image } from 'react-native';

// Так мы отображаем картинку из локального каталога
<Image
  source={require('./assets/logo.png')}
  style={{ width: 100, height: 100 }}
/>

// Здесь картинка загружается из сети
<Image
  source={{ uri: 'https://reactnative.dev/img/logo-og.png' }}
  style={{ width: 200, height: 80 }}
/>
  • Свойство source отвечает за путь к картинке.
  • Свойство style обязательно должно содержать размеры (ширина и высота). Без них компонент не увидит картинки.

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

Работа с локальными изображениями

Когда вы хотите добавить картинку, которая будет идти вместе с приложением, используйте команду require. Файл должен лежать внутри вашего проекта, например, в папке assets.

<Image
  source={require('./assets/photo.jpg')} // путь относительно текущего файла
  style={{ width: 150, height: 150 }}
/>
  • Такой подход удобен, когда картинки статичны и не меняются.
  • Изображения, подключённые через require, включаются в сборку приложения и не зависят от интернета.

Загрузка изображений из интернета

Часто нужно показывать картинки из внешних источников через ссылку (url). Тогда source будет объект с полем uri:

<Image
  source={{ uri: 'https://example.com/image1.png' }}
  style={{ width: 200, height: 150 }}
/>
  • По умолчанию React Native загружает изображение с сети и отображает его.
  • Не забывайте задавать размеры в style. Без них картинка не появится!

Работа с форматами изображений

React Native поддерживает форматы PNG, JPG и GIF. С SVG ситуация сложнее: для SVG требуется подключать дополнительные библиотеки (например, react-native-svg), так как стандартный компонент Image не умеет работать с этим форматом.

npm install react-native-svg
import SvgUri from 'react-native-svg-uri';

<SvgUri
  width="100"
  height="100"
  source={{uri:'https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/android.svg'}}
/>

Обратите внимание: для SVG это уже другой компонент, и у него свои особенности.

Размеры, стилизация и адаптация изображений

Явное указание размеров

Проще всего задать вместе с компонентом:

<Image
  source={require('./assets/icon.png')}
  style={{ width: 72, height: 72 }}
/>
  • Не задав размеры, вы столкнётесь с пустым местом на экране.

Масштабирование с помощью resizeMode

У компонента Image есть свойство resizeMode, которое определяет, как масштабируется изображение в заданных границах:

  • cover — масштабирует, чтобы заполнить всё пространство (часть картинки может обрезаться).
  • contain — вписывает полностью в доступные размеры (могут остаться пустые области).
  • stretch — растягивает до размеров.
  • center — размещает картинку по центру без масштабирования.
  • repeat — фон из повторяющихся изображений (работает не во всех платформах).
<Image
  source={{ uri: 'https://example.com/photo.jpg' }}
  style={{ width: 300, height: 100 }}
  resizeMode="contain" // попробуйте поменять на cover, stretch и посмотрите отличия
/>

Округление, рамки и стили

Стилизация работает так же, как с любым другим View или Text:

<Image
  source={{ uri: 'https://example.com/user.jpg' }}
  style={{
    width: 120,
    height: 120,
    borderRadius: 60, // делает изображение круглым
    borderWidth: 2,
    borderColor: 'tomato',
  }}
/>
  • Если хотите сделать идеально круглым — ширина и высота должны совпадать, а borderRadius равняться половине ширины/высоты.

Работа с прогрессом загрузки, ошибками и плейсхолдерами

Отображение плейсхолдера пока изображение загружается

Стандартный Image не предоставляет встроенных событий для отслеживания статуса загрузки. Но вы можете реализовать подобное поведение при помощи композиции нескольких компонентов:

import React, { useState } from 'react';
import { View, Image, ActivityIndicator, StyleSheet } from 'react-native';

const RemoteImage = ({ uri, style }) => {
  const [loading, setLoading] = useState(true);

  return (
    <View style={style}>
      {loading && (
        <ActivityIndicator
          style={StyleSheet.absoluteFill}
          size="large"
          color="#888"
        />
      )}
      <Image
        source={{ uri }}
        style={StyleSheet.absoluteFill}
        onLoadEnd={() => setLoading(false)} // скрываем спиннер после загрузки
      />
    </View>
  );
};
  • Здесь мы показываем индикатор загрузки пока картинка скачивается.
  • Пример, как это выглядит на практике.

Обработка ошибок загрузки изображения

Если изображение не грузится (например, битая ссылка), используйте событие onError, чтобы подменить изображение или показать ошибку:

import React, { useState } from 'react';
import { Image } from 'react-native';

const FallbackImage = ({ uri, fallbackSource, style }) => {
  const [error, setError] = useState(false);

  return (
    <Image
      source={error ? fallbackSource : { uri }}
      style={style}
      onError={() => setError(true)} // меняем source на запасной, если ошибка загрузки
    />
  );
};
  • Это позволит не показывать пустое место, если изображение не загрузилось.

Оптимизация и кэширование изображений

Почему кэширование важно

Картинки из сети могут быть большими и долго грузиться. Без кэширования пользователю придется скачивать их каждый раз заново. В стандартном компоненте Image Android и iOS умеют кэшировать изображения автоматически, но контроль над этим ограничен.

Если задача требует контроля кэша или показа изображений в офлайн-режиме — лучше использовать сторонние библиотеки.

Использование react-native-fast-image

Одна из самых популярных библиотек для оптимизации работы с изображениями — react-native-fast-image. Она дает:

  • Улучшенное кэширование
  • Поддержку прогресса загрузки
  • Опцию для выбор способа кэширования

Установка:

npm install react-native-fast-image

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

import FastImage from 'react-native-fast-image';

<FastImage
  style={{ width: 200, height: 200 }}
  source={{
    uri: 'https://example.com/image.jpg',
    priority: FastImage.priority.high,
    cache: FastImage.cacheControl.immutable, // всегда использовать оригинальное изображение из кэша
  }}
  resizeMode={FastImage.resizeMode.cover}
/>
  • FastImage полностью повторяет интерфейс стандартного компонента Image с дополнительными возможностями.

Реализация интерактивных и анимированных изображений

Зум, скроллинг и другие интерактивные эффекты

Если вам нужно, чтобы пользователь мог масштабировать изображение (например, картинка товара или аватар) — используйте готовые пакеты типа react-native-image-zoom-viewer или оборачивайте Image в ScrollView с опцией zoom:

import { ScrollView, Image } from 'react-native';

// картинка, которую можно масштабировать
<ScrollView
  minimumZoomScale={1}
  maximumZoomScale={3}
  contentContainerStyle={{ alignItems: 'center', justifyContent: 'center' }}
>
  <Image
    source={{ uri: 'https://example.com/large-photo.png' }}
    style={{ width: 300, height: 300 }}
  />
</ScrollView>

Анимации изображений

Для анимации появления изображения используйте Animated API:

import React, { useRef, useEffect } from 'react';
import { Animated, Image } from 'react-native';

const FadeInImage = ({ source, style }) => {
  const opacity = useRef(new Animated.Value(0)).current;

  useEffect(() => {
    Animated.timing(opacity, {
      toValue: 1,
      duration: 700,
      useNativeDriver: true,
    }).start();
  }, []);

  return (
    <Animated.Image
      source={source}
      style={[style, { opacity }]} // анимация появляется плавно
    />
  );
};
  • Этот пример показывает, как реализовать плавное появление картинки.

Платформенные особенности и ограничения

Ограничения Android и iOS

  • На Android поддерживается большая часть функциональности Image, кроме некоторых режимов resizeMode.
  • iOS и Android кэшируют изображения по-разному — это может влиять на работу с сетевыми картинками, когда вы ожидаете одинакового поведения на обеих платформах.
  • На Android иногда возникают проблемы с отображением больших изображений — приложение может упасть из-за нехватки памяти.

Работа с большим количеством или большими изображениями

Если у вас список из множества картинок (например, галерея), обязательно используйте FlatList или SectionList с правильным использованием props like removeClippedSubviews и оптимизируйте отображение:

import { FlatList, Image } from 'react-native';

const images = [
  { id: '1', uri: 'https://example.com/ph1.png' },
  { id: '2', uri: 'https://example.com/ph2.png' },
  // ...
];

<FlatList
  data={images}
  keyExtractor={item => item.id}
  renderItem={({ item }) => (
    <Image source={{ uri: item.uri }} style={{ width: 100, height: 100 }} />
  )}
  removeClippedSubviews
/>
  • FlatList рендерит только видимые элементы, экономя память.

Продвинутые возможности

Динамическая подгрузка изображений

Когда вы знаете только имя файла или ссылку и хотите динамически подгружать изображения:

  • Локальные изображения через require не поддерживают динамическую подгрузку. Вам нужно заранее импортировать путь или использовать switch/case для выбора нужного require.
  • Для работы с массивами фото из сети проще использовать url.

Обработка EXIF, ориентация фотографий

Для чтения EXIF-данных (например, ориентации фото из камеры) можно использовать библиотеку react-native-exif или react-native-image-picker. Это позволит корректно отображать фотографии, сделанные на устройствах с разной ориентацией камеры.

Использование градиентов поверх изображений

Можно легко добавить градиент поверх картинки, используя пакет react-native-linear-gradient и абсолютное позиционирование:

import LinearGradient from 'react-native-linear-gradient';

<View style={{ width: 200, height: 200 }}>
  <Image
    source={{ uri: 'https://example.com/photo.jpg' }}
    style={{ width: 200, height: 200, position: 'absolute' }}
  />
  <LinearGradient
    colors={['transparent', 'rgba(0,0,0,0.5)']}
    style={{ width: 200, height: 200, position: 'absolute' }}
  />
</View>
  • Такой подход часто применяют для затемнения нижней части карточек с текстом.

Заключение

Работа с изображениями в React Native включает множество аспектов: от базового вывода и задания размеров до кастомизации, оптимизации загрузки, обработки ошибок и обеспечения высокого UX. Важно понимать, как выбирается источник изображения, как задаются его размеры, как показаны плейсхолдеры и что делать в случае ошибки. Сторонние библиотеки помогают закрыть большинство сложных случаев (кэширование, SVG, прогресс загрузки). Обязательно учитывайте разницу между платформами и уделяйте внимание производительности, особенно если работаете с большим количеством картинок.

Оптимизация изображений — лишь одна из многих задач при разработке React Native приложений. Для создания профессионального и удобного приложения необходимо уметь создавать компоненты, управлять навигацией и состоянием, а также работать с нативными модулями. На нашем курсе React Native и Expo Router вы найдете все необходимые знания для освоения React Native разработки. В первых 3 модулях уже доступно бесплатное содержание — начните погружаться в мир React Native прямо сегодня.

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

Вопрос 1: Как динамически выводить локальные картинки по имени файла из массива?

Ответ: Для локальных файлов через require нельзя использовать строковые пути. Используйте объект с именами файлов и заранее импортированными require-ссылками.

const images = {
  'user1': require('./assets/user1.jpg'),
  'user2': require('./assets/user2.jpg'),
};
// images[name] теперь можно передавать в source

Вопрос 2: Как обрабатывать клики по изображению?

Ответ: Оберните Image в TouchableOpacity или TouchableWithoutFeedback и добавьте обработчик onPress.

import { TouchableOpacity, Image } from 'react-native';

<TouchableOpacity onPress={() => alert('Картинка нажата!')}>
  <Image source={...} style={{width: 100, height: 100}} />
</TouchableOpacity>

Вопрос 3: Почему gif-анимации иногда не работают на Android?

Ответ: Для анимации gif на Android требуется установка dependency Fresco или использование сторонних библиотек вроде react-native-fast-image.

Вопрос 4: Как получить реальный размер картинки до загрузки (например, чтобы правильно рассчитать layout)?

Ответ: Используйте метод Image.getSize(uri, success, failure):

Image.getSize('https://example.com/photo.jpg', (width, height) => { 
  // width и height — реальные размеры
})

Вопрос 5: Можно ли сжать или уменьшить размеры изображения перед загрузкой/отправкой на сервер?

Ответ: Используйте библиотеки типа react-native-image-resizer или react-native-image-crop-picker. Они позволяют обрезать и изменять размер изображений на устройстве до отправки.

Стрелочка влевоКак создать модальные окна в 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 ₽
Подробнее

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