This media is not supported in your browser
VIEW IN TELEGRAM
Разработчик создал библиотеку androidx-splashscreen-compose (не от Google решение), которая позволяет делать красивую анимацию как на анимашке.
Подробный разбор и реализация есть в статье (EN,6м, альт. ссылка) или
#android #compose
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥51👍7🤔2
#compose #navigation
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11
🚀 Отказываюсь от Списков в пользу Сеток в UI
Раньше для списков в Compose я по привычке использовал LazyColumn. Но чем больше работаю с адаптивными интерфейсами, тем очевиднее: это никуда не годиться и надо использовать доступное пространство, а не тупо растягивать интерфейс. Перехожу на Grid компоновку✔️
LazyVerticalGrid позволяет задать фиксированную ширину колонки, и система сама рассчитает, сколько их поместится на экране.
В результате:
1️⃣ адаптивность «из коробки» на телефонах, планшетах и больших экранах
2️⃣ минимум дополнительного кода,
3️⃣ единый компонент вместо костылей для разных форм-факторов.
Определение количества колонок происходит на основе политики GridCell:
📱 На маленьком экране это будет 2–3 колонки, а на планшете — уже 5–6, и всё это без ручной логики.
Есть еще более гибкий вариант если элементы строк должны быть разной высоты - LazyVerticalStaggeredGrid (стиль как в Pinterest)
❗️ Теперь я придерживаюсь строго правила:
🔗 Очень хорошо построение списков осветили в документации по Lazy Layout
Аналогично можно проделать и с RecyclerView, использую вместо LinearLayoutManager вариант с сеткой - GridLayoutManager или StaggeredGridLayoutManager, только там не будет автоматического расчета колонок на основе доступного места. Это придется реализовывать самостоятельно.
✍️ Что думаете о таком подходе для UI? Ударит по производительности?
#ui #android #compose
Раньше для списков в Compose я по привычке использовал LazyColumn. Но чем больше работаю с адаптивными интерфейсами, тем очевиднее: это никуда не годиться и надо использовать доступное пространство, а не тупо растягивать интерфейс. Перехожу на Grid компоновку
LazyVerticalGrid позволяет задать фиксированную ширину колонки, и система сама рассчитает, сколько их поместится на экране.
В результате:
LazyVerticalGrid(
columns = GridCells.Adaptive(minSize = 120.dp),
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(8.dp)
) {
items(100) { Item(...) }
}
Определение количества колонок происходит на основе политики GridCell:
// всегда N колонок
GridCells.Fixed(N)
// автоматический расчет на основе минимальной ширины колонки
GridCells.Adaptive(minSize = 120.dp)
// каждая ячейка шириной 100dp
GridCells.FixedSize(100.dp)
📱 На маленьком экране это будет 2–3 колонки, а на планшете — уже 5–6, и всё это без ручной логики.
Есть еще более гибкий вариант если элементы строк должны быть разной высоты - LazyVerticalStaggeredGrid (стиль как в Pinterest)
LazyVerticalStaggeredGrid(
columns = Adaptive(minSize = 150.dp),
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(8.dp)
) {
items(100) { Item(...) }
}
Если не могу явно сформулировать почему интерфейс должен быть в одну колонку, то вертикальный список брать не стоит!
🔗 Очень хорошо построение списков осветили в документации по Lazy Layout
Аналогично можно проделать и с RecyclerView, использую вместо LinearLayoutManager вариант с сеткой - GridLayoutManager или StaggeredGridLayoutManager, только там не будет автоматического расчета колонок на основе доступного места. Это придется реализовывать самостоятельно.
#ui #android #compose
Please open Telegram to view this post
VIEW IN TELEGRAM
14👍95🤔18🔥9🏆9❤2🙏1
📸 Вышла Jetpack CameraX 1.5.0 с новыми фичами и готовым UI для видоискателя камеры
Что нового
🤖 Camera Viewfinder - первый релиз стабильный релиз UI для показа камеры с простым встраиванием в UI (View и Compose)
⚙️ Первый релиз
🛠 Исправление багов
#android #камера #jetpack #compose
Что нового
androidx.camera:camera-compose - работа с камерой в Compose UI🛠 Исправление багов
// Пример View Finder в Compose
val currentSurfaceRequest: SurfaceRequest
by viewModel.surfaceRequests.collectAsState()
val coordinateTransformer = remember { MutableCoordinateTransformer() }
CameraXViewfinder(
surfaceRequest = surfaceRequest,
// Can also use EMBEDDED
implementationMode = ImplementationMode.EXTERNAL,
modifier =
modifier.pointerInput(Unit) {
detectTapGestures {
with(coordinateTransformer) {
val surfaceCoords = it.transform()
viewModel.focusOnPoint(
surfaceRequest.resolution,
surfaceCoords.x,
surfaceCoords.y
)
}
}
},
coordinateTransformer = coordinateTransformer
)
#android #камера #jetpack #compose
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥33❤10👍9
Forwarded from Compose Broadcast
This media is not supported in your browser
VIEW IN TELEGRAM
Как была сделана реализация написали в статье, а исходники есть на GitHub
#compose
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥88👍13❤3
Android-приложения запускаются на экранах с разными размерами и ориентацией. Чтобы интерфейс выглядел хорошо в любых условиях, стоит учитывать несколько простых правил, которые я выработал за годы опыта 👇
Фиче может быть выделен весь экран, часть окна или вообще маленький контейнер. Пусть она сама решает: занять всё пространство или только необходимое. Остальное — задача хоста, который через параметры (например, Modifier в Compose) подстроит отображение или сама правильно разместит (например, по центру).
Вместо
LazyColumn — лучше LazyVerticalGrid, а для RecyclerView — GridLayoutManager. Они умеют подстраивать сетку под свободное место на экране.Пользователь может менять скейл интерфейса: Google позволяет масштабировать всё, увеличивая DP → PX. Поэтому всегда предусмотрите скролл, если контента может стать больше.
Фича отвечает только за свой UI. А вот приложение решает, как её показать: в одну панель или, например, в связке через
ListDetailPaneScaffold, где на экране могут быть сразу несколько экранов.Даже если дизайнер подготовил макет только под смартфон в вертикали — попробуйте включить воображение. Немного гибкости и масштабирования дадут пользователям куда более удобный опыт без больших трудозатрат.
📚 Что почитать:
- Практики по построению адаптивных приложений
- Compose Material 3 Adaptive
- Jetpack WindowManager
- Как строить адаптивный UI через layout
💬 Делитесь в комментариях своими советами и болями адаптивности UI
#android #ui #compose #adaptive #ux #material3
Please open Telegram to view this post
VIEW IN TELEGRAM
19👍48🔥8❤3🤯3
Media is too big
VIEW IN TELEGRAM
🎙 Проводит — Алексей Панов @kotlin_adept
🗓 Понедельник, 20 октября, 19:00 (GMT+3)
Kotlin Multiplatform (KMP) набирает всё большую популярность — растёт количество вакансий и интерес со стороны компаний.
Я давно хотел провести реальное собеседование, где Android-разработчика с опытом в KMP будут спрашивать на позицию, где придётся писать на KMP каждый день:
иногда с использованием Compose, а иногда — только шаря логику между платформами.
Будет жарко 🔥
Алексей — один из самых опытных разработчиков, кто давно пишет KMP в проде и отлично понимает экосистему.
Кстати, у него классный Telegram-канал @kotlin_adept — там много полезных инсайтов про KMP.
❗️Запись собеседования появится на канале после эфира.
#AndroidBroadcast #kmp #compose #собеседование #android
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥46👍14❤4
Вот реальная история, как знание механики работы ViewModel спасло мне вечер 👇
У меня приложение на Compose и Jetpack Navigation 3 (работает на основе состояния Back Stack). Экран «Навигатор файлов» открывает папки рекурсивно: по сути это тот же экран, но с другими данными. Все данные — из одной и той же❗️ Баг: при переходе в папку навигация срабатывает, UI не меняется. Современные ИИ подсказали общие вещи, но не помогли — промты, видимо, подвели (тут мне ещё надо прокачать знания) 🙂
Вспомнил ключевой факт про архитектуру:
👉 Все
👉 В пределах одного
👉 Если нужно несколько экземпляров одного типа на одном owner’е — используем key.
Решение в одну строку — привязать ключ к ViewModel, связанный с текущей папкой:
Мини-чеклист, если ловите такой баг
👉 Один экран используется повторно с разными параметрами? → Нужен key.
👉 Меняется route, но owner тот же? → key обязателен.
👉 Используете Hilt/Koin? → У этих функций тоже есть параметр key (hiltViewModel(key=...), koinViewModel(key=...)).
👉 key должен детерминированно зависеть от входных данных (например, folderId).
👉 При навигации назад убедитесь, что ViewModel освобождается ожидаемо.
Ещё нюанс - если у вас сложная иерархия графов, проверьте, к какому
Рекомендую посмотреть мои видео по теме:
📹 Разбор Jetpack Navigation 3
🪙 Полный разбор Jetpack ViewModel в Android и Kotlin Multiplatform
#android #compose #androidjetpack #viewmodel #архитектура
У меня приложение на Compose и Jetpack Navigation 3 (работает на основе состояния Back Stack). Экран «Навигатор файлов» открывает папки рекурсивно: по сути это тот же экран, но с другими данными. Все данные — из одной и той же
ViewModel.Вспомнил ключевой факт про архитектуру:
👉 Все
ViewModel живут в ViewModelStore.👉 В пределах одного
ViewModelStoreOwner (Activity/Fragment/NavBackStackEntry) получение ViewModel по умолчанию идёт по типу.👉 Если нужно несколько экземпляров одного типа на одном owner’е — используем key.
Решение в одну строку — привязать ключ к ViewModel, связанный с текущей папкой:
@Composable
fun FileNavigator(
folderId: Id,
modifier: Modifier = Modifier,
) {
// новый folderId → новый экземпляр ViewModel → новый UI-стейт
val viewModel: FileNavigatorViewModel = viewModel(
key = "files(rootId='$folderId')"
)
// ...
}
Мини-чеклист, если ловите такой баг
👉 Один экран используется повторно с разными параметрами? → Нужен key.
👉 Меняется route, но owner тот же? → key обязателен.
👉 Используете Hilt/Koin? → У этих функций тоже есть параметр key (hiltViewModel(key=...), koinViewModel(key=...)).
👉 key должен детерминированно зависеть от входных данных (например, folderId).
👉 При навигации назад убедитесь, что ViewModel освобождается ожидаемо.
Ещё нюанс - если у вас сложная иерархия графов, проверьте, к какому
ViewModelStoreOwner вы реально привязаны.Рекомендую посмотреть мои видео по теме:
#android #compose #androidjetpack #viewmodel #архитектура
Please open Telegram to view this post
VIEW IN TELEGRAM
12👍87🤔10🤯5❤2🔥2
Если коротко про изменения — Material3 Adaptive всё ближе к полноценному “Responsive Compose”. Теперь можно писать интерфейсы, которые одинаково естественно ведут себя на телефоне, планшете и десктопе.
Главное:
🪶 Levitate-стратегия для ThreePaneScaffold — превращает панель в плавающее окно (popup).
↔️ Reflow-стратегия для ThreePaneScaffold — позволяет при узком экране уводить одну панель под другую, сохраняя UX.
👉 PaneScaffoldScope.saveableStateHolder — сохраняет состояние между разными конфигурациями экрана.
👉 Modifier.preferredHeight() — теперь можно задать предпочтительную высоту панели.
📏 Новые WindowSizeClasses: API currentWindowAdaptiveInfo() теперь распознаёт Large и ExtraLarge окна — важный шаг к поддержке планшетов и десктопов.
👉 Drag-to-resize получил настройку пользовательского поведения и поддержку a11y (accessibility).
#compose #material3 #adaptive #android #jetpack
Please open Telegram to view this post
VIEW IN TELEGRAM
👍18❤9🔥2
📦 Не храните всю графику в приложении
Одна из лучших практик — храните в приложении только простые иконки в векторном формате, а всю растровую графику держите в облаке. Особенно это важно для приложений, которые не могут работать офлайн 🌐
Почему это стоит делать:
🚀 Меньше вес приложения → быстрее установка и обновления
📉 Не тянете лишние ресурсы, которые пользователь никогда не увидит (например, фичи под подпиской или в определённом регионе)
🌍 Можно адаптировать загрузку под регион, тариф или подписку
💰 Гибкость — обновляйте, отключайте или заменяйте контент без релиза
Как хранить изображения правильно:
- Векторные иконки → храним в ресурсах приложения
- Баннеры, иллюстрации, фото → CDN или облако (Firebase Storage, CloudFront, S3 и др.) Для загрузки используйте image loader: Coil, Glide, Picasso и т.д.
Чтобы грузить локальные ресурсы в Android через URL можно использовать адреса (примеры для приложения с именем пакета
- По имени ресурса
- По числовому ID
⚙️ Для Compose Multiplatform пока нет прямой поддержки таких ссылок, но можно расширить любой image loader и добавить обработку собственных URL или типов данных
#android #оптимизация #compose #coil
Одна из лучших практик — храните в приложении только простые иконки в векторном формате, а всю растровую графику держите в облаке. Особенно это важно для приложений, которые не могут работать офлайн 🌐
Почему это стоит делать:
🚀 Меньше вес приложения → быстрее установка и обновления
📉 Не тянете лишние ресурсы, которые пользователь никогда не увидит (например, фичи под подпиской или в определённом регионе)
🌍 Можно адаптировать загрузку под регион, тариф или подписку
💰 Гибкость — обновляйте, отключайте или заменяйте контент без релиза
Как хранить изображения правильно:
- Векторные иконки → храним в ресурсах приложения
- Баннеры, иллюстрации, фото → CDN или облако (Firebase Storage, CloudFront, S3 и др.) Для загрузки используйте image loader: Coil, Glide, Picasso и т.д.
Чтобы грузить локальные ресурсы в Android через URL можно использовать адреса (примеры для приложения с именем пакета
com.example.myapp):- По имени ресурса
android.resource://com.example.myapp/drawable/my_image- По числовому ID
android.resource://com.example.myapp/2130837504#android #оптимизация #compose #coil
Please open Telegram to view this post
VIEW IN TELEGRAM
🤯13❤8👍8