Карусель изображений в React Native

Карусели  —  важнейший инструмент для отображения нескольких элементов контента в одном месте. Допустим, вы владеете успешным интернет-магазином и хотите разместить на сайте каталог с предложениями и скидками  —  тогда целесообразно оформить его в виде карусели. При таком подходе список не занимает много места, тем самым улучшая дизайн UX.

Перед вами один из примечательных примеров карусели в приложении Instagram:

Создание карусели с помощью React Native включает следующие этапы: 

  • применение компонента React Native FlatList API для отображения элементов и настройки горизонтальной ориентации списка; 
  • написание дополнительного кода для показа пользовательской анимации при пролистывании слайдера;  
  • создание функциональности пагинации. Благодаря ей пользователь будет знать число элементов, представленных в карусели. 

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

Просто воспользоваться React Native Snap Carousel. Это библиотека с открытым исходным кодом, позволяющая с легкостью создавать элементы карусели. Перечислим ее преимущества: 

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

С преимуществами ознакомились  —  займемся делом! 

В данном обучающем руководстве создадим карусель изображений с кнопками навигации. По итогам работы получим результат: 

Настройка проекта 

Инициализация 

Прежде всего, с помощью Expo создаем репозиторий React Native. Для этого выполняем следующую команду терминала: 

expo init carouse-native-tutorial

Expo предлагает выбрать шаблон. На этом этапе отдаем предпочтение minimal workflow

Установка зависимостей 

В данном проекте потребуется лишь модуль react-native-snap-carousel для создания слайд-шоу и карусели: 

npm install react-native-snap-carousel

Создание карусели 

Таблица стилей 

В корневой директории проекта создаем файл styles.js, в котором будет содержаться код, необходимый для проектирования интерфейса. 

В styles.js пишем код: 

import { Dimensions, StyleSheet, Platform } from 'react-native';

const { width: screenWidth } = Dimensions.get('window');
const styles = StyleSheet.create({
container: {
paddingTop: 30,
},
title: {
fontSize: 20,
},
item: {
width: '100%',
height: screenWidth - 20, //высота на 20 единиц меньше, чем ширина экрана.
},
imageContainer: {
flex: 1,
borderRadius: 5,
backgroundColor: 'lightblue',
marginBottom: Platform.select({ ios: 0, android: 1 }), //обработка ошибки отображения.
},
  • Строка 3: Получаем ширину устройства пользователя через модуль Dimensions
  • Строки 8–10: Стиль title меняет размер шрифта соответствующего элемента, приравнивая его к 20 единицам. 
  • Строки 11–14: Свойство item отвечает за стиль элементов карусели. Здесь мы сообщаем React, что элементы слайд-шоу будут занимать всю доступную ширину. 
  • Строки 15–20:imageContainer представляет стиль карусели  — закругляются края с помощью свойства borderRadius

Далее добавляем данный фрагмент кода в тот же файл, как показано ниже: 

image: {
...StyleSheet.absoluteFillObject,
resizeMode: 'contain',
},
dotContainer: {
backgroundColor: 'rgb(230,0,0)',
},
dotStyle: {
width: 10,
height: 10,
borderRadius: 5,
backgroundColor: 'black',
},
inactiveDotStyle: {
backgroundColor: 'rgb(255,230,230)',
},
});
export default styles;
  • Строки 1–4:image оформляет стиль элементов карусели. 
  • Строки 5–15: Задействуем свойства dotContainer , dotStyle и inactiveDotStyle для стилизации компонента пагинации. Об этой операции поговорим чуть позже. 
  • Строка 18: Экспортируем конфигурацию styles, тем самым связывая стили с проектом. 

Источник данных 

В проекте создаем новый файл data.js, в котором перечисляем изображения, предназначенные для демонстрации в слайдере. 

В этом файле создаем массив объектов, каждый из которых содержит поля source , title и description:

const data = [
{
title: "Coral Reef",
description: "Location: Red Sea",
source:
"https://images.unsplash.com/photo-1633205719979-e47958ff6d93?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=387&q=80",
},
{
title: "Phone",
description: "iPhone 6 on the table",
source:
"https://images.unsplash.com/photo-1535303311164-664fc9ec6532?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=387&q=80",
},

{
title: "Old building",
description: "Location: Germany",
source:
"https://images.unsplash.com/photo-1623345805780-8f01f714e65f?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=387&q=80",
},
];
export default data;

Элемент карусели 

В корневой директории проекта создаем файл CarouselItem.js, ответственный за отрисовку изображений в карусели. 

В CarouselItem.js прописываем следующий код: 

import React from 'react';
import { ParallaxImage } from 'react-native-snap-carousel';
import { View, Text, Pressable, SafeAreaView } from 'react-native';
import styles from './styles';

function CarouselItem({ item, index }, parallaxProps) {
return (
<Pressable onPress={() => alert('Image description:' + item.description)}>
<SafeAreaView style={styles.item}>
<ParallaxImage
source={{ uri: item.source }} /* источник изображения */
containerStyle={styles.imageContainer}
style={styles.image}
{...parallaxProps} /* передача необходимых свойств */
/>
  • Строка 6: CarouselItem принимает свойства, содержащие важную информацию об источнике данных. 
  • Строка 8: Модуль Pressable сообщает приложению, что пользователь может взаимодействовать с данным компонентом. Обработчик onPress информирует программу, что при нажатии пользователем на элемент React должен вывести описание изображения во всплывающем окне. 
  • Строки 10: Компонент ParallaxImage показывает изображения в слайд-шоу. 

Закончив с этой частью, добавляем в тот же файл код: 

/* CarouselItem.js */ 
<Text style={styles.title} numberOfLines={2}>
{item.title}
</Text>
</SafeAreaView>
</Pressable>
);
}

export default CarouselItem;
  • Строка 3: Отображаем поле изображения title
  • Строка 10: Экспортируем элемент CarouselItem, что означает возможность применения этого пользовательского модуля в проекте. 

Элемент карусели готов, далее переходим к слайдеру. 

Настройка слайдера 

Начнем с файла CustomSlider.js, в котором пропишем код:  

import * as React from 'react';
import { View, Text } from 'react-native';

export default function CustomSlider({ data }) {
console.log(data);
return (
<View>
<Text> Hello, world</Text>
</View>
);
}
  • Строка 4: Компонент CustomSlider принимает свойство data. Это будет источник данных. 
  • Строка 5: В целях отладки выводим значение data.

Осталось лишь отобразить модуль CustomSlider в UI. Для этого переходим в App.js и меняем весь код на следующий: 

import React from 'react';
import { View } from 'react-native';
import data from './data';
import CustomSlider from './CustomSlider';
// Вы можете импортировать из локальных файлов

// или любого чистого модуля javascript, доступного в npm
export default function App() {
return (
<View>
<CustomSlider data={data} />
</View>
);
}
  • Строка 6: Отрисовываем CustomSlider и передаем источник данных в аргумент data

Получаем результат: 

Как видно, React вывел данные в консоль. А это значит, что код работает! 

Создание слайдера

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

Для этого заменяем весь код в CustomSlider.js на следующий: 

import { Dimensions } from "react-native";
import Carousel from "react-native-snap-carousel";
import CarouselItem from "./CarouselItem";
import styles from "./styles";

const { width } = Dimensions.get("window");
export default function CustomSlider({ data }) {
const settings = {
sliderWidth: width,
sliderHeight: width,
itemWidth: width - 80,
data: data,
renderItem: CarouselItem,
hasParallaxImages: true,
};
return (
<View style={styles.container}>
<Carousel {...settings} />
</View>
);
}
  • Строки 8: Объект settings содержит конфигурацию карусели
  • Строка 13: Сообщаем React Native, что CarouselItem отвечает за демонстрацию элементов на стороне фронтенда. 
  • Строка 18: Отрисовываем карусель и передаем конфигурацию. 

Получаем результат:

Как видим, у нас появился прекрасно работающий слайдер. А это значит, что с кодом все в порядке! 

Методы навигации 

В этом разделе предоставим пользователю управление каруселью с помощью элементов Button

В CustomSlider.js добавляем указанный фрагмент: 

import { useRef } from "react";
import { Button } from "react-native";

const carouselRef = useRef(null);
return (
<View style={styles.container}>
<Carousel
ref={carouselRef}
/*further code... */
/>
  • Строка 4: Создаем экземпляр useRef, предназначенный для управления слайд-шоу. 
  • Строка 8: Компоненту Carousel присваиваем хук carouselRef и получаем возможность выполнять методы навигации. 

Далее вносим следующий код в блок return в том же файле: 

//код для добавления блока return в CustomSlider.js 
<View>
<Button
onPress={() => carouselRef.current.snapToItem(0)}
title="Go to start"
/>
<Button
onPress={() => carouselRef.current.snapToItem(data.length - 1)}
title="Go to end"
/>
</View>
  • Строки 3–6: Метод snapToItem осуществляет переход к слайду с указанным индексом. В данном случае мы инструктируем React Native перенаправить пользователя к первому изображению. 
  • Строки 7–9: При нажатии перенаправляем пользователя к последнему изображению в массиве. 

Ниже представлен результат: 

Пользовательские компоненты пагинации 

Задача данного раздела  —  применить пагинацию с помощью компонента Pagination. Этот шаг позволит улучшить дизайн интерфейса. 

Сначала создаем файл CustomPaging.js, в котором пишем код: 

import * as React from 'react';
import { Pagination } from 'react-native-snap-carousel';
import styles from './styles';

export default function CustomPaging({ data, activeSlide }) {
const settings = {
dotsLength: data.length,
activeDotIndex: activeSlide,
containerStyle: styles.dotContainer,
dotStyle: styles.dotStyle,
inactiveDotStyle: styles.inactiveDotStyle,
inactiveDotOpacity: 0.4,
inactiveDotScale: 0.6,
};
return <Pagination {...settings} />;
}
  • Строка 5: Данный компонент принимает 2 свойства: data (список изображений) и activeSlide (текущий индекс слайдера). 
  • Строка 6: Переменная settings содержит конфигурацию Pagination
  • Строка 15: Передаем конфигурацию и отображаем компонент Pagination

Затем переходим в CustomSlider.js и добавляем код: 

import CustomPaging from "./CustomPaging";
//дополнительный код удален для краткости
const [slideIndex, setSlideIndex] = useState(0);
const settings = {
onSnapToItem: (index) => setSlideIndex(index), //добавляем его в переменную 'settings'.
};
return (
<View style={styles.container}>
<Carousel ref={carouselRef} {...settings} />
<CustomPaging data={data} activeSlide={slideIndex} />
</View>
);
  • Строка 3: Создаем хук slideIndex. Исходя из имени, эта переменная указывает на текущий индекс карусели. 
  • Строка 5: Обработчик onSnapToItem запускается каждый раз, когда пользователь сдвигает изображения слайд-шоу. Здесь мы инструктируем React Native обновлять переменную slideIndex согласно текущему номеру слайда. 
  • Строка 10: Отображаем компонент CustomPaging, а также передаем источник данных и состояние slideIndex в качестве свойств. 

Цель достигнута! 

Дополнительные ресурсы 

Исходный код проекта на Expo

Заключение 

На основе материала статьи вы узнали, как создать простой слайдер изображений с помощью библиотеки React Native Snap Carousel. Ее документация понятна и лаконична, что позволяет без особых усилий приступить к разработке каруселей изображений.

Читайте также:

Читайте нас в TelegramVK и Яндекс.Дзен


Перевод статьи Hussain Arif: Build an Image Carousel In React Native

Предыдущая статьяТрассировка стека и более точная отладка
Следующая статьяКак успешно реализовать проверку состояния контейнера в Docker Compose