Android | Михаил Белый

Android | Михаил Белый 

Все про Android

43subscribers

46posts

goals1
$15.17 of $1 366 raised
Поплыву на остров Ко Мадсум кормить диких кабанчиков

Как делать сайт на Kotlin + Compose

В этом посте будет рассказано как создавался сайт
MobileDevEmoji, от идеи до публикации. И с какими проблемами пришлось столкнуться на пути реализации всех хотелок. На все ушло несколько дней. Знаний JavaScript не потребовалось.
Для минимального MVP нам нужен список эмодзи на 8 столбиков, как в телеграме. При клике показываем увеличенное превью с названием. В телеге такого функционала нет, какой перед нами логотип бывает не понятно.
Так как в Web-разработке я полный дубень, делать сайт будем на знакомых технологиях: Kotlin + Compose. WASM (WebAssembly) в мультиплатформе пока что в статусе alpha, но уже хорошо работает.
Быстренько набросал на бумаге эскиз:
Клонирую официальный шаблон проекта Kotlin Multiplatform Wizard с чекбоксом Web.
Все что нам нужно из библиотек:
Создаю список на 200 элементов, чтобы посмотреть как будет отображаться. Scaffold + TopAppBar, внутри – LazyVerticalGrid на 8 столбиков. При клике на айтем – справа выезжает превью внутри AnimatedVisibility.

Создание списка:

Код экрана:

Далее в репозиторий добавляются SVG-иконки:

Хранить их будем в JSON:
Начинаем чесать репу каким образом их отрисовать. Знакомый мне Coil
как оказалось не умеет отображать SVG в мультиплатформе, только в Android. И вообще рекомендует SVG перегонять в XML (Android Vector) и складывать в папку composeResources. Пробую конвертировать SVG в XML через
этот сайт и обнаруживаю, что отваливается поддержка масок. От этой идеи приходится отказаться.
Дальше нахожу библиотеку Sketch. На гитхабе они хвалятся, что умеют в SVG. Затащил их тарантас, запустил – грохнулся от нехватки памяти. Оказывается иконки нужно копировать в папку build и дергать оттуда. Зачем? Не смог разобраться с этим решением, иду дальше.
Обнаруживаю, что JetBrains поддерживает движок Skia. Он умеет массив байтов перегонять в SVG и нативно рисовать его через обычный Painter в Compose. Подключать ничего дополнительно не нужно, работает из коробки.

Проект готов! Запускается и тыкается.
Начинаю чесать лысину куда его захостить. Выбор пал на бесплатный GitHub Pages. Он дает нам 2 способа собрать наш сайт: из ветки репозитория или через CI (GitHub Actions). Сначала пробую из ветки, используя инструкцию от JetBrains по генерации WebApp и видос какого-то испанца на ютубе. Не работает. Сайт не генерируется. Берусь за второй способ - сборка через CI. Подрезаю конфигурацию из этого примера, немного изменив ее под свой проект.

Ура, сайт собрался. Даже появилась ссылка на github.io. Но что я вижу? Черный экран и не единой иконки.
Начинаю раскопки в чем может быть дело. Тут даже непонятно как запрос сформулировать. Вообще без понятия, почему в собранном проекте SVG-файлы присутствуют, но ничего не отображается. Дошел до 3 страницы гугла, поспрашивал в чатиках, напряг чатгпт. Пошел в поиск по репозиториям гитхаба посмотреть, кто сталкивался с аналогичным. На четвертой репке раскурил, что Web-приложения не поддерживают загрузку файлов из директории
src/commonMain/composeResources/files напрямую через путь. Там у меня лежали SVG-файлы. Кто бы мог подумать.
Переложил их в src/commonMain/resources/files. Начал дергать методом
readResourceBytes и все заработало.

Проверяю работу сайта во всех браузерах. Открываю сафари и вижу черный экран смерти. Оказывается поддержку WASM GC (штука для мультиплатформы) сюда еще не завозили. В хромобраузерах работает отлично. Добавляю в проект поддержку JavaScript. Это довольно просто:
После этого собираем уже не wasmJsApp, а jsApp. Этот таргет работает везде.
Теперь накинем немного оптимизаций. Чтобы отрисовать 200 иконок нужно достать их из файловой системы, перегнать в ByteArray, потом перегнать в
Painter и начать отрисовывать. Довольно ресурсоемкая задача. При первом прогоне занимает какое-то время. Сначала у меня был лоадинг по центру экрана и приходилось пялил на счетчик, прежде чем обозреть весь список.
А хотелось бы не ждать пока все иконки сконвертятся, а отображать их по мере загрузки. С обычным List<Emoji> такое не сработает.
У нас изначально есть не пустой список из 200 элементов. По мере загрузки нам нужно обновлять ячейки, добавляя туда иконку. Для этого в Compose есть SnapshotStateList и mutableStateListOf.
Методом copy обновляем поле painter внутри Emoji. Получается красивая поочередная загрузка.

При наведении курсора на иконку будем ее красиво анимированно увеличивать
Далее при тестировании на мобилках оказалось что показывать превью справа от списка не лучшая идея. На экранах смартфонов контент не влезает. Принято решение использовать всплывающий по центру ModalBottomSheet.
Вообще в Compose мощный инструментарий для адаптации UI под все размеры экранов. Но пока нет желания в него закапываться.
Сайт успешно отображает 200 иконок из первого набора. Хотим добавить еще 200 из второго. И как-нибудь их визуально разделить. Еще желательно использовать Один List<Emoji> и один LazyVerticalGrid. Внезапно эта вьюха поддерживает заголовки. Добавляем header шириной 8 клеток, для этого заюзаем span:
Далее добавляем 200 иконок из первого пака, откусывая от списка emojiList
первые 200 элементов:

Добавляем второй header:

И еще 200 иконок, откусывая уже 200 последних элементов:

Отображаются 400 иконок в виде двух наборов по 200 штук.
Открывать ссылки на эмодзипаки (кнопки Get on Telegram, иконки на фигму и телегу в тулбаре) будем инструментарием композа:

На этом все. Спасибо за внимание.
Перейти на сайт:
https://michaelbel.github.io/MobileDevEmoji
Исходники на гитхабе:
https://github.com/michaelbel/MobileDevEmoji
Subscription levels1

Жалкий детский уровень

$1.37 per month
• Бесконечный респект и признательность 
• Ранний доступ к видео и воркшопам
• Отдельный топик в телеграм-чате с записями реальных Android-собеседований
• Отдельный топик с автоматическими новостями про Android-разработку
+ chat
Go up