Обычно новым фреймворкам не хватает хороших примеров использования, туториалов и инструментов. Но не в случае с Jetpack Compose: параллельно с разработкой фреймворка Google развивал репозиторий, богатый на примеры использования. Вырисовывался набор полезных утилит, переиспользуемых виджетов и прочих удобств для разработки.  Так из репозитория с примерами вырос Accompanist — набор библиотек для Jetpack Compose, которые можно добавить в свой проект как зависимость. В статье рассмотрим подробнее, какой инструментарий он предоставляет. В легаси-проекте тема может быть достаточно большой, иметь большое поддерево тем и кастомных атрибутов. В легаси-проектах обычно это AppCompat тема, в то время как Compose использует MaterialTheme. Поэтому нужен «мост» между двумя темами. В составе Accompanist есть AppCompatTheme — удобная обёртка, которая перенесёт тему из мира легаси и XML в мир Compose. Исходники простые: их можно дополнить или сделать по образу свою реализацию, если в теме много кастомных параметров. Если проект уже использует Material Design Theme, то, согласно, документации, надо использовать MDC-Android Compose Theme Adapter из Material Design Components. SystemUiController — удобная обёртка над WindowInsetsControllerCompat. Помогает из кода управлять свойствами системных баров: видимостью и цветом. Незаменимая вещь, если вы поддерживаете в проекте API от версии 21 (Android 5.0). Insets — обёртка над WindowInsetsCompat и набор расширений для совместимости с Compose. Поможет подписаться на изменения Inset’ов. Кроме параметров из WindowInsetsCompat, можно использовать расширения для Modifier. Для работы с padding’ами: Для работы с размерами: Работа с опасными разрешениями требует некоторых усилий. Нужно: Запросить разрешение у пользователя. С помощью кастомного диалога (view, snackbar и других) объяснить пользователю, зачем нужно разрешение. Правильно обработать ответ пользователя. Предоставить возможность перейти в настройки приложения, чтобы пользователь мог принять решение, какие доступы дать. Разработчики Accompanist проделали большую работу, чтобы работать с разрешениями было удобно. И что самое классное, они сделали запрос разрешений через ActivityResultLauncher: никакого больше переопределения onActivityResult в Activity, и теперь явно прописывается контракт для запроса разрешения. API достаточно простое. permissionState — состояние с параметрами разрешения. Кроме boolean флагов, нужен для запроса разрешения. permissionNotGrantedContent — контент для состояния, когда нет разрешения. permissionNotAvailableContent — контент для состояния, когда разрешение нельзя запросить. Тогда пользователя надо направить в настройки приложения. content — контент для состояния, когда пользователь дал разрешение. Request Permission Sample FlexBoxLayout — контейнер для гибкой вёрстки. С ним удобно располагать элементы по горизонтали или вертикали: например, чтобы отобразить коллекцию элементов. Он сам рассчитает размеры и поймёт, как лучше перенести элемент на следующую строку или столбец. FlexBox для Android — не родной контейнер для вёрстки. Первую версию FlexBoxLayout для CSS представили в 2009 году. До мира Android-разработки он добрался сильно позже: в 2016 году вышла первая alpha версия. С того времени вышло немало релизов, самый свежий — 3.0.0.  Также вышел FlexBoxLayoutManager для RecyclerView. Вещь удобная, и она не могла не появиться в Compose. Только назвали контейнер по-другому: FlowLayout. Название не менее лаконичное — и так же точно передаёт суть его работы. Как и его предки, имеет такие же параметры для вёрстки. Поэтому если вы с ними уже встречались ранее, то и в Compose верстать с его помощью будет несложно. SwipeRefreshLayout — один из самых известных и используемых контейнеров в Android разработке. Использовать его просто: в XML необходимо контейнер с контентом обернуть в SwipeRefreshLayout и в коде реализовать интерфейс OnRefreshListener — например, чтобы начать перезагрузку контента на экране. Вроде всё хорошо, больше ничего и не надо.  Трудности начинаются, если разработчику нужно кастомизировать внешний вид лоадера. Возможности кастомизации ограничены — несмотря на громоздкую реализацию (~1200 строк).  «Из коробки» можно изменить цвет стрелки, размер и появление индикатора. Если вам необходимо изменить цвет индикатора или (о боже) «а давайте как на iOS», то придётся искать стороннюю библиотеку или писать самостоятельно. Но и то, и другое занимает время и несёт риски. Accompanist помогает решить эти проблемы.  В Accompanist отсутствует XML, но принцип использования не изменился: контент всё так же оборачиваем в SwipeRefresh и используем лямбду для действия при обновлении. Рассмотрим, что SwipeRefresh умеет «из коробки» и что с возможностью кастомизации. state — хранит состояние загрузки и прогресс анимации индикатора. onRefresh — лямбда-триггер для старта, например, перезагрузки контента. modifier — модификатор контейнера: размеров, отступов и так далее. swipeEnabled — включение и выключение реакции контейнера на свайп. refreshTriggerDistance задаёт расстояние до триггера анимации. Чем расстояние больше, тем позже индикатор отреагирует на свайп. indicatorAlignment — аналог Gravity. Интересная функциональность, которая пригодится, скорее, при реализации кастомного индикатора. indicatorPadding — простая кастомизация отступов индикатора. Можно сделать отступ с определённой стороны, можно равный со всех. indicator — реализация индикатора. «Из коробки» есть стандартная реализация индикатора из material design. Можно модифицировать её или написать полностью свою. clipIndicatorToPadding — флаг, позволяющий обрезать индикатор по отступу контента. content — непосредственно сам контент внутри SwipeRefresh. Примеры работы SwipeRefresh из семпла библиотеки Accompanist. SwipeRefreshBasicSample SwipeRefreshTweakedIndicatorSample SwipeRefreshCustomIndicatorSample SwipeRefresh уже «из коробки» предоставляет неплохие возможности кастомизации привычного Android-разработчикам SwipeRefreshLayout. Реализация контейнера и индикатора занимает примерно 600 строк. На UI языке Pager — горизонтальный или вертикальный список, у которого каждый элемент занимает всю или почти всю область экрана. Ключевое отличие от обычного списка — Snap-эффект, то есть «доскрол» элемента. Pager, или ViewPager, имел несколько стадий развития как UI элемент в Android. Сначала был ViewPager, позже появился RecyclerView, и его приспособили под пейджинг. Сравнительно недавно появился ViewPager2, который под капотом использует тот же RecyclerView.  Давайте взглянем, как Pager может выглядеть на «языке» Compose. ViewPager, ViewPager2 и RecyclerView имеют общую черту: как UI-элементам для отображения коллекций, им нужен адаптер для заполнения данными. Pager на Compose этого лишён: взамен адаптера необходимо инициализировать PagerState. С него и начнём. Параметров немного, а для инициализации обязательный всего один. pageCount — количество элементов, currentPage — текущая страница, currentPageOffset — отступ страницы. Имеет значение от 0.0 до 1.0. Можно использовать для программного скролла страницы. offscreenLimit — лимит страниц для подгрузки: количество подгружаемых элементов слева и справа от текущего элемента. infiniteLoop — зацикленный скролл. Сразу видно, какая функциональность «из коробки» самая крутая — конечно же, это зацикленный скролл. Сколько же было написано костылей для зацикливания ViewPager и RecyclerView :)  Accompanist предлагает две реализации для пейджера: HorizontalPager и VerticalPager. Если взглянуть в исходники, и то, и другое — просто обёртка на Compose функцией  Pager. Разница только в инициализации параметра isVertical. Многие параметры могут быть знакомы по RecyclerView и ViewPager. Поэтому рассмотрим те,  которые не встречаются у них «из коробки». verticalAlignment — аналог Gravity. Используется для центровки элемента: например, чтобы элемент доскроливался не до центра, а до края контейнера. horizontalAlignment — аналогично vercticalAligment, только для горизонтали. flingBehavior — конфиг поведения скрола: настраивает анимацию, когда пользователь перестаёт скролить или бросает скрол. Эти параметры примечательны тем, что у ViewPager и RecyclerView они не настраиваются легко «из коробки». Для ViewPager придётся «шаманить» с параметрами адаптера и с самим ViewPager. У RecyclerView для доскрола используются наследники SnapHelper’а. В коде всё выглядит достаточно просто: инициализируем PagerState и заполняем пейджер элементами. Часто пейджеры используются с индикаторами страниц, табами, а также трансформацией страниц при свайпе. И для этого у Accompanist’а тоже есть решение. Как я писал выше, состояние Pager’a хранится в PagerState. Для анимации индикаторов, трансформации страниц работы с табами его можно переиспользовать. Очень удобно: одно состояние для всех компонент — нет необходимости проставлять слушателей. Как бонус — получаем минимальную связность. Coil (Coroutine Image Loader) —  сравнительно новая библиотека: первая версия вышла в 2019 году. Написана на Kotlin и Coroutines — и в этом её преимущество перед Glide и Picasso. У неё простое и гибкое API, она легко интегрируется с проектами на Kotlin, а ещё умеет работать с Svg, Gif и видео.  До недавнего времени Accompanist тоже имел в арсенале интеграцию с Coil и Glide. С версии 0.15.0 этот инструментарий помечен как Deprecated: разработчики Coil добавили поддержку Compose и сделали это на основе Accompanist с небольшими изменениями. Поэтому далее код будет из примера работы Coil, а не Accompanist. Чтобы понять, как происходит интеграция Coil и Compose, рассмотрим параметры элемента ImageView в Compose. Почти все могут быть знакомы Android-разработчику. painter — сущность для отрисовки графики. Это может быть цвет, Bitmap или Vector. contentDescription — cпециальный параметр для работы с Accessibility. Вы же хороший разработчик и не ставите туда null? :) modifier — модификатор для выставления параметров элемента: размера, отступов и так далее. alignment — аналог Gravity. contentScale — аналог ScaleType из ImageView. alpha — прозрачность для отрисовки painter. colorFilter — цветовой фильтр для отрисовки painter. Вся магия происходит в painter — точнее, в наследниках абстрактного класса Painter. Собственно, Coil для интеграции предоставляет свои реализации Painter’a.  CrossFadePainter отрисовывает cross fade переход между двумя Painter’ами. DrawablePainter — cамый простой представитель Painter’ов из библиотеки, но не менее полезный. Умеет отображать Drawable и AnimatableDrawable. ImagePainter умеет больше всех. Поддерживает загрузку String, Uri ("android.resource", "content", "file", "http", and "https"), HttpUrl, File, DrawableRes, Drawable, Bitmap.  ImageRequest и ImageLoader — базовые классы из Coil. С помощью ImageRequest настраиваются параметры загрузки картинки: ссылка, листенеры, политика кеширования и декодинга. ImageLoader запускает ImageRequest, содержит настройки для работы с изображениями. Как правило он настраивается один раз и переиспользуется во всём приложении. Skeleton-загрузчики уже давно стали стандартом для многих платформ. Во время загрузки пользователь видит псевдовёрстку экрана: по размеру и форме фигур он может предположить, где будет текст, где — фото, а где — кнопка. Это создаёт у пользователя позитивные впечатления. Accompanist предлагает несколько реализаций placeholder’ов для создания skeleton загрузчиков:  Базовая — placeholder без анимаций.  Fade — placeholder c fade-анимацией.  Shimmer — placeholder c анимацией мерцания. У Accompanist ещё не вышла версия 1.0, а инструментарий библиотеки уже достаточно богатый и поможет обойти кучу граблей.  Стоит заметить, что Accompanist — не единственная библиотека, которая поможет в поддержке и интеграции с Compose. Уже есть интеграция Compose c Hilt, Rx, Jetpack Navigation, Jetpack Paging. В Lottie 4.0.0 тоже добавили поддержку Compose. Больше полезного про Android — в нашем телеграм-канале Surf Android Team. Здесь мы публикуем кейсы, лучшие практики, новости и вакансии Surf, а также проводим прямые эфиры. Присоединяйтесь! Кейсы Surf на сайте >>  Android developer