React Native предоставляет "из коробки" Image.prefetch
, который может быть полезен для предварительной загрузки изображений, но в некоторых случаях этого недостаточно.
Вам действительно нужно, чтобы изображение присутствовало локально, чтобы избежать эффекта мерцания при его загрузке. Это также позволяет лучше контролировать кеш изображений. В приведенном ниже примере вы видите разницу между использованием Image.prefetch
кэша изображений и локальным обслуживанием изображения.
Вам также может потребоваться отобразить ваше изображение в другом компоненте, отличном от <Image>
. Например, в приведенном ниже примере мы используем <SVGImage>
, который работает только для локальных путей и / или URI данных.
Используйте ExpoKit
Поэтому вам нужно хранить изображения локально. Если вы уже используете expo, из коробки есть Библиотека файловой системы. Если ваш проект отключен, кажется, что библиотека react-native-fetch-blob
потеряла своего основного участника. В прошлый раз, когда я его использовал, возникли некоторые проблемы. Возможно, стоит добавить ExpoKit в качестве зависимости вашего проекта, даже если вы оторваны с самого начала. ExpoKit включает множество других замечательных компонентов, в том числе BlurView
, которые можно анимировать в исходном виде, если вы также хотите реализовать прогрессивную загрузку изображений.
Работа с параллелизмом на Android
Многие компоненты могут одновременно отображать одно и то же изображение. И выполнение Filesystem.exists(localURI)
операции на Android вернет истину, даже если загрузка файла не завершена. Это означает, что вам необходимо реализовать шаблон наблюдателя, чтобы загружать каждое изображение только один раз и получать уведомление, когда загрузка изображения завершена. В response-native-expo-image-cache API выглядит так:
import {CacheManager} from "react-native-expo-image-cache";
// Remote URI
const {uri} = this.props;
CacheManager.cache(uri, localURI => this.setState({ uri: localURI }));
Ниже представлена реализация наблюдателя:
static async cache(uri: string, listener: Listener): Promise<void> {
const {path, exists} = await getCacheEntry(uri);
// Is the image is already downloading, we just listen
if (isDownloading(uri)) {
addListener(uri, listener);
// If it's not downloading and it exists, we serve it
} else if (exists) {
listener(path);
// Else, we download the image and notify everyone when done
} else {
addListener(uri, listener);
await FileSystem.downloadAsync(uri, path);
notifyAll(uri, path);
unsubscribe(uri);
}
}
Прогрессивная загрузка изображений
Каждый раз, когда URI изображения сохраняется в базе данных, сохраняйте его предварительный просмотр в формате base64 вместе с ним. Это позволит вам загружать изображение очень плавно. Ниже приведен пример:
{
preview: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==",
uri: "https://firebasestorage.googleapis.com/v0/b/react-native-e.appspot.com/o/b47b03a1e22e3f1fd884b5252de1e64a06a14126.png?alt=media&token=d636c423-3d94-440f-90c1-57c4de921641"
}
Теперь вы можете сразу отобразить размытую версию превью и уменьшить размытие до 0 при загрузке полной версии изображения. В iOS <BlurView>
от ExpoKit удобно поддерживает собственный драйвер анимации. Однако Android по умолчанию не использует анимированный вид непрозрачности. Я сделал запрос на вытягивание к BlurView.android.js
, чтобы протестировать воду и выяснить, будет ли команда открыта для реализации <BlurView>
, которая была бы более симметричной на обеих платформах. А пока вы можете реализовать свои собственные. Вот как это выглядит в response-native-expo-image-cache:
// intensity is an Animated.Value
const opacity = intensity.interpolate({
inputRange: [0, 100],
outputRange: [0, 1]
});
{
Platform.OS === "ios" && (
<AnimatedBlurView
tint="dark"
style={computedStyle}
{...{intensity}}
/>
)
}
{
Platform.OS === "android" && (
<Animated.View
style={[computedStyle, { backgroundColor: "rgba(0, 0, 0, 0.5)", opacity }]}
/>
)
}
В ‹Image› есть серьезная ошибка.
"Вот этот". У вас может возникнуть соблазн установить URI в состоянии вашего компонента изображения: установите его на URI данных предварительного просмотра, а затем на полное изображение при загрузке. Проблема в том, что иногда изображение не обновляется. Вы можете использовать key
для принудительного обновления, но оно будет мерцать. Решение? Наложите полное изображение на предварительный просмотр. Опять же, вот как это выглядит в response-native-expo-image-cache:
{
// If show the preview if it exists
hasPreview && (
<RNImage
source={{ uri: preview }}
resizeMode="cover"
style={computedStyle}
/>
)
}
{
// If the image is loaded, we show it on top
// this.onLoadEnd is used to start the deblurring animation
(uri && uri !== preview) && (
<RNImage
source={{ uri }}
resizeMode="cover"
style={computedStyle}
onLoadEnd={this.onLoadEnd}
/>
)
}
Это все, ребята!
Мы никогда не закончим говорить об изображениях в React Native. Это мой список 5 лучших. Мне не хватает каких-то предметов? Пожалуйста, дайте знать, а пока удачного взлома 🎉
Ищете красивые комплекты пользовательского интерфейса? Я реализую все экраны и компоненты из Sketch Elements в React Native. Вы можете получить его здесь". Я также публикую сеансы программирования в реальном времени и обучающие программы на моем канале Youtube.