Перейти к содержанию

Изображения

Ресурсы статических изображений

React Native предоставляет унифицированный способ управления изображениями и другими медиаактивами в приложениях для Android и iOS. Чтобы добавить статическое изображение в свое приложение, поместите его в дерево исходного кода и сделайте на него ссылку следующим образом:

1
<Image source={require('./my-icon.png')} />

Имя изображения определяется так же, как и имя JS-модуля. В приведенном выше примере пакет будет искать my-icon.png в той же папке, что и требующий его компонент.

Вы можете использовать суффиксы @2x и @3x, чтобы предоставить изображения для различных плотностей экрана. Если у вас следующая структура файла:

1
2
3
4
5
6
.
├── button.js
└── img
    ├── check.png
    ├── [email protected]
    └── [email protected]

...и код button.js содержит:

1
<Image source={require('./img/check.png')} />

...бандлер свяжет и подаст изображение, соответствующее плотности экрана устройства. Например, [email protected] будет использоваться на iPhone 7, а [email protected] — на iPhone 7 Plus или Nexus 5. Если изображение, соответствующее плотности экрана, отсутствует, будет выбран ближайший лучший вариант.

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

Вот некоторые преимущества, которые вы получаете:

  1. Одинаковая система на Android и iOS.
  2. Изображения находятся в той же папке, что и код JavaScript. Компоненты самодостаточны.
  3. Нет глобального пространства имен, т.е. вам не нужно беспокоиться о коллизии имен.
  4. Только те изображения, которые действительно используются, будут упакованы в ваше приложение.
  5. Добавление и изменение изображений не требует перекомпиляции приложения, вы можете обновить симулятор, как вы это обычно делаете.
  6. Пакетник знает размеры изображения, нет необходимости дублировать их в коде.
  7. Изображения можно распространять с помощью пакетов npm.

Для того чтобы это работало, имя изображения в require должно быть известно статически.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// GOOD
<Image source={require('./my-icon.png')} />;

// BAD
var icon = this.props.active
    ? 'my-icon-active'
    : 'my-icon-inactive';
<Image source={require('./' + icon + '.png')} />;

// GOOD
var icon = this.props.active
    ? require('./my-icon-active.png')
    : require('./my-icon-inactive.png');
<Image source={icon} />;

Обратите внимание, что источники изображений, требуемые таким образом, включают информацию о размере (ширина, высота) для изображения. Если вам нужно масштабировать изображение динамически (т.е. с помощью flex), вам может понадобиться вручную установить {width: undefined, height: undefined} в атрибуте style.

Статические ресурсы, не относящиеся к изображениям

Синтаксис require, описанный выше, может быть использован для статического включения аудио-, видео- или документальных файлов в ваш проект. Поддерживаются самые распространенные типы файлов, включая .mp3, .wav, .mp4, .mov, .html и .pdf. Полный список смотрите в bundler defaults.

Вы можете добавить поддержку других типов, добавив опцию assetExts resolver option в Metro configuration.

Оговорка заключается в том, что видео должны использовать абсолютное позиционирование вместо flexGrow, поскольку информация о размере в настоящее время не передается для активов, не являющихся изображениями. Это ограничение не действует для видео, которые связаны непосредственно в Xcode или в папке Assets для Android.

Изображения из ресурсов гибридного приложения

Если вы создаете гибридное приложение (часть пользовательского интерфейса на React Native, часть — в коде платформы), вы все равно можете использовать изображения, которые уже встроены в приложение.

Для изображений, включенных через каталоги активов Xcode или в папку Android drawable, используйте имя изображения без расширения:

1
2
3
4
<Image
    source={{ uri: 'app_icon' }}
    style={{ width: 40, height: 40 }}
/>

Для изображений в папке активов Android используйте схему asset:/:

1
2
3
4
<Image
    source={{ uri: 'asset:/app_icon.png' }}
    style={{ width: 40, height: 40 }}
/>

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

Сетевые изображения

Многие изображения, которые вы будете отображать в своем приложении, не будут доступны во время компиляции, или вы захотите загрузить некоторые динамически, чтобы уменьшить размер двоичного файла. В отличие от статических ресурсов, вам нужно будет вручную указать размеры изображения. Настоятельно рекомендуется использовать https, чтобы соответствовать требованиям App Transport Security на iOS.

1
2
3
4
5
6
// GOOD
<Image source={{uri: 'https://reactjs.org/logo-og.png'}}
       style={{width: 400, height: 400}} />

// BAD
<Image source={{uri: 'https://reactjs.org/logo-og.png'}} />

Сетевые запросы на изображения

Если вы хотите установить такие вещи, как HTTP-Verb, заголовки или тело вместе с запросом изображения, вы можете сделать это, определив эти свойства для объекта источника:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<Image
    source={{
        uri: 'https://reactjs.org/logo-og.png',
        method: 'POST',
        headers: {
            Pragma: 'no-cache',
        },
        body: 'Your Body goes here',
    }}
    style={{ width: 400, height: 400 }}
/>

Изображения данных Uri

Иногда вы можете получить закодированные данные изображения из вызова REST API. Вы можете использовать схему uri 'data:' для использования этих изображений. Как и для сетевых ресурсов, вам нужно будет вручную указать размеры изображения.

Рекомендуется только для очень маленьких и динамических изображений, например, иконок в списке из БД.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// include at least width and height!
<Image
    style={{
        width: 51,
        height: 51,
        resizeMode: 'contain',
    }}
    source={{
        uri:
            'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADMAAAAzCAYAAAA6oTAqAAAAEXRFWHRTb2Z0d2FyZQBwbmdjcnVzaEB1SfMAAABQSURBVGje7dSxCQBACARB+2/ab8BEeQNhFi6WSYzYLYudDQYGBgYGBgYGBgYGBgYGBgZmcvDqYGBgmhivGQYGBgYGBgYGBgYGBgYGBgbmQw+P/eMrC5UTVAAAAABJRU5ErkJggg==',
    }}
/>

Контроль кэша (только для iOS)

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

  • default: Использовать стратегию по умолчанию родной платформы.
  • reload: Данные для URL будут загружены из исходного источника. Никакие существующие данные кэша не должны использоваться для удовлетворения запроса на загрузку URL.
  • force-cache: Существующие кэшированные данные будут использованы для удовлетворения запроса, независимо от их возраста или срока действия. Если в кэше нет существующих данных, соответствующих запросу, данные загружаются из исходного источника.
  • only-if-cached: Существующие данные в кэше будут использованы для удовлетворения запроса, независимо от их возраста или срока действия. Если в кэше, соответствующем запросу на загрузку URL, нет существующих данных, попытка загрузить данные из исходного источника не предпринимается, и загрузка считается неудачной.
1
2
3
4
5
6
7
<Image
    source={{
        uri: 'https://reactjs.org/logo-og.png',
        cache: 'only-if-cached',
    }}
    style={{ width: 400, height: 400 }}
/>

Образы локальной файловой системы

Смотрите CameraRoll для примера использования локальных ресурсов, которые находятся за пределами Images.xcassets.

Лучшее изображение в рулоне камеры

iOS сохраняет несколько размеров для одного и того же изображения в Camera Roll, очень важно выбрать максимально близкий по производительности. Вы не захотите использовать в качестве источника изображение полного качества 3264x2448 при отображении миниатюры 200x200. Если есть точное совпадение, React Native выберет его, в противном случае он будет использовать первое изображение, которое по крайней мере на 50% больше, чтобы избежать размытия при изменении размера с близкого размера. Все это делается по умолчанию, поэтому вам не нужно беспокоиться о написании утомительного (и чреватого ошибками) кода, чтобы сделать это самостоятельно.

Почему бы не изменить размер всего автоматически?

Если вы не укажете размер изображения, браузер отобразит элемент 0x0, загрузит изображение, а затем отобразит его с правильным размером. Большой проблемой такого поведения является то, что ваш пользовательский интерфейс будет прыгать по всему сайту при загрузке изображений, что создает очень плохой пользовательский опыт.

В React Native это поведение намеренно не реализовано. Разработчику приходится больше работать, чтобы заранее знать размеры (или соотношение сторон) удаленного изображения, но мы считаем, что это приводит к лучшему пользовательскому опыту. Статические изображения, загруженные из пакета приложения с помощью синтаксиса require('./my-icon.png'), могут быть автоматически подобраны по размеру, поскольку их размеры доступны непосредственно во время установки.

Например, результатом require('./my-icon.png') может быть:

1
{"__packager_asset":true,"uri":"my-icon.png","width":591,"height":573}

Источник как объект

В React Native одним из интересных решений является то, что атрибут src называется source и принимает не строку, а объект с атрибутом uri.

1
<Image source={{ uri: 'something.jpg' }} />

Со стороны инфраструктуры причина в том, что это позволяет нам прикрепить метаданные к этому объекту. Например, если вы используете require('./my-icon.png'), то мы добавляем информацию о его фактическом расположении и размере (не полагайтесь на этот факт, он может измениться в будущем!). Это также задел на будущее, например, мы можем захотеть в какой-то момент поддерживать спрайты, вместо вывода {uri: ...}, мы можем вывести {uri: ..., crop: {left: 10, top: 50, width: 20, height: 40}} и прозрачно поддерживать спрайты на всех существующих сайтах вызова.

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

Фоновое изображение через вложение

Частым запросом разработчиков, знакомых с вебом, является функция фон-изображение. Для решения этой задачи вы можете использовать компонент <ImageBackground>, который имеет те же пропсы, что и <Image>, и добавить к нему дочерние элементы, которые вы хотите разместить поверх него.

В некоторых случаях вы можете не использовать <ImageBackground>, поскольку его реализация является базовой. Обратитесь к документации <ImageBackground>, чтобы узнать больше, и при необходимости создайте свой собственный компонент.

1
2
3
4
5
return (
  <ImageBackground source={...} style={{width: '100%', height: '100%'}}>
    <Text>Inside</Text>
  </ImageBackground>
);

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

Стили радиуса границы iOS

Обратите внимание, что следующие свойства стиля радиуса границы, специфичные для угла, могут быть проигнорированы компонентом изображения iOS:

  • borderTopLeftRadius
  • borderTopRightRadius
  • borderBottomLeftRadius
  • borderBottomRightRadius

Внепоточное декодирование

Декодирование изображения может занимать более одного кадра. Это один из основных источников падения кадров в Интернете, поскольку декодирование выполняется в основном потоке. В React Native декодирование изображения выполняется в другом потоке. На практике вам уже нужно обрабатывать случай, когда изображение еще не загружено, поэтому отображение заполнителя еще на несколько кадров во время декодирования не требует изменения кода.

Настройка лимитов кэша изображений iOS

На iOS мы предоставляем API для переопределения стандартных ограничений кэша изображений React Native. Его следует вызывать из кода вашего родного AppDelegate (например, в didFinishLaunchingWithOptions).

1
RCTSetImageCacheLimits(4*1024*1024, 200*1024*1024);

Параметры:

Name Type Required Description
imageSizeLimit number Yes Image cache size limit.
totalCostLimit number Yes Total cache cost limit.

В приведенном выше примере кода ограничение размера изображения установлено на 4 МБ, а ограничение общей стоимости — на 200 МБ.

Комментарии