Из этой статьи вы узнаете как создать галерею для просмотра фотографий с динамическим размером ячеек и выбором фотографий
В этой статье вы прочитаете:
Примеры изображений и кода из этой статьи доступны на GitHub
Как создать фото-галерею
Чтобы создать фото-галерею необходимо 3 компонента:
Источник фотографий
Шаблон фотографии
Лента для вывода фотографий
Источник фотографий
Под источником фотографий я подразумеваю объект, который будет сообщать ленте о том, сколько есть фотографий и принимать событие о том, что ленту докрутили до конца и нужно загрузить ещё фотографий.
💡 Добавление/удаление фотографий будет описано в одной из будущих статей
Сами фотографии могут загружаться через Core Data, Swift Data, из сети по API. Мой проект использует Realm. Для примера приложение будет загружать фотографии из временной папку, куда будут скопированы ресурсы.
Источник фотографий - это объект типа ObservableObject - специальный тип объекта, который при изменении свойств, помеченных как published будет вызывать обновление состояния View.
Массив фотографий
Состояние активной загрузки
У загрузки будет три состояния:
Сама фотография должна хранить в себе ссылку на изображение, а также флаг качества фотографии. Также будет необходим уникальный ID для вывода списка фото в галерее и для выбора фотографий
Загрузка фотографий
Также потребуется метод loadMore, который будет вызываться для дозагрузки фото. Этот метод будет вызываться при скролле галереи.
Загрузка фотографий будет выполняться пачками. Загружать фото будет выполнять объект, который будет реализует протокол ContentSource. В метод загрузки будет передаваться последняя фотография в ленте и размер пачки.
💡 Это позволит переключаться между разными хранилищами, я использую Realm и отладочные хранилища с разными фотографиями.
Сам метод loadMore будет выставлять режим загрузки, получать новые фотографии и анализировать. Если пусто, то будет выставляться режим done, иначе - hasMore
💡Здесь нет обработки ошибок, чтобы не загромождать пример
Автоматическая загрузка
Автоматическая загрузка будет осуществляться аналогично примеру с исчезающими боковыми кнопками. Потребуется два GeometryReader:
Разница этих двух значений больше нуля будет означать, что нижняя граница фотографий находится выше нижнего края экрана. Если при этом галерея находится в режиме hasMore, можно загрузить ещё фотографий.
Шаблон фотографии
Шаблон фотографии - это ZStack, в котором будет находиться изображение, а также в углах будут находиться индикаторы для выбора фото и качества фотографии
Фотографии большие, поэтому загружать их целиком при каждом отображении ленты будет слишком накладно - будет нужна загрузка, масштабирование и обрезка. Чтобы этого избежать необходимо кэширование изображений.
💡 Кэш - это специальное временное хранилище, которое позволяет повысить скорость загрузки изображений за счет расходов памяти телефона. Кэш на диске будет хранить изображения между запусками, а кэш в памяти позволяет быстрее просматривать те, что были недавно использованы
В проекте я буду использовать библиотеку Kingfisher для загрзки фотографий с диска и кэширования. Но для примера воспользуюсь AsyncImage, чтобы не добавлять лишних зависимостей.
В приложении будет 3 размера фотографий, поэтому необходимо будет передавать размер фотографии в шаблон, чтобы кэш корректно работал. Также параметром будет флаг того, что фотография выбрана.
Лента для вывода фотографий
Для отображения галереи потребуется ScrollView, внутри которого будут LazyVGrid и индикатор загрузки. Внутри галереи фотографии будут выводиться через ForEach для массива.
Необходимо добавить GeometryReader для определения размера фотографии.
Как реализовать выбор фотографий
Для выбора фото необходимо создать массив с ID фотографий. Галерея будет проверять наличие ID фотографии в этом массиве и выставлять флаг Selected. Нажатие на фотографию буде добавлять и удалять ID в массив.
💡 Кнопка выбора фотографии добавляется как overlay. Чтобы она была прозрачной в её label добавляется Color.clear, но для того, чтобы её можно было нажать, необходимо ей задать "тело" прямоугольной формы с помощью contentShape и clipShape
Переход на просмотр фотографии и включение режима редактирования будут в одной из будущих статей.
Как сделать переключение размера фото
В галерее будет три режима вывода фотографии, мелкие, средние и крупные фотографии. Если взять средний iPhone, например 14, то на экране будет 5, 3 и 1 соответственно. Конечно выводить в ленте по 1 фото на экран iPad Pro будет слишком, поэтому на планшетах будет примерно такой же размер фотографий.
LazyVGrid позволяет задать автоматическое определение количества колонок для размеров ячеек в границах размера. Необходимо создать enum с тремя параметрами размера фото, а также массив размеров фотографий.
Изменять размер фотографии будут три кнопки внизу галереи, они будут созданы аналогично кнопкам панелей, но будет дополнительный слой, отображающий текущую выбранную кнопку.
Выглядеть и работать переключение будет так
При переключении на маленькие изображения заметен лаг, который связан с необходимость в моменте пережать большие изображения под меньший размер. Кэширование изображений маленького размера решает этот вопрос
Заключение
В этой статье я рассказал о том, как создать галерею фотографий, сделать возможность их выбора и добавить переключение размера.
Все работающие примеры есть в проекте на Github, их можно скачать и запустить.
Пишите в комментариях интересующие вас темы для будущих статей, а чтобы их не пропустить - подписывайтесь на дневник.