База знаний android
1 subscriber
2.48K photos
284 videos
2 files
3.77K links
Download Telegram
Forwarded from Android Good Reads
Strong Skipping Mode не делает типы stable, лишь позволяет skip’ать composable с unstable параметрами, если передан тот же самый объект по ссылке ===, тогда как stable типы по-прежнему сравниваются через equals() из-за этого он не помогает, если создаются новые инстансы (типа listOf(), copy()), и рекомпозиция всё равно происходит, поэтому stability позволяет пропускать перерисовку для разных объектов с одинаковыми данными, а Strong Skipping - это оптимизация для случаев с переиспользованием одной и той же ссылки, а не замена пониманию стабильности

Внутри много кода, а не воды для самопроверки
Forwarded from Mobile Compose
This media is not supported in your browser
VIEW IN TELEGRAM
#Compose #UI #Animation #Debugging

🎨 Compose 1.11.0 — Визуальная отладка анимаций

Shared Elements анимации и работа с Modifier.animatedBounds стали прозрачнее благодаря инструменту LookaheadAnimationVisualDebugging.

Ключевые возможности:

▫️Прямо в Runtime можно увидеть траектории движения объектов и их целевые границы (target bounds).
▫️Визуализация помогает понять, почему элемент «прыгает» или обрезается при переходе между экранами.

Инструмент полезен в первую очередь для сложных UI-переходов, где раньше приходилось полагаться только на логи и интуицию.

🎨 Mobile Compose 💬 Чат канала
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Compose Broadcast
This media is not supported in your browser
VIEW IN TELEGRAM
⚙️ Отладка shared element анимаций в Compose 1.11 стала проще. Появилась функция LookaheadAnimationVisualDebugging, визуализирующая анимацию

#Compose
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Compose Broadcast
// Пример использования
LookaheadAnimationVisualDebugging(
overlayColor = Color(0x4AE91E63),
isEnabled = true,
multipleMatchesColor = Color.Green,
isShowKeylabelEnabled = false,
unmatchedElementColor = Color.Red,
) {
SharedTransitionLayout {
CompositionLocalProvider(
LocalSharedTransitionScope provides this,
) {
// your content
}
}
}


#Compose
Forwarded from Compose Broadcast
🤖 Styles API в Compose: революция в кастомизации UI

До недавнего времени стилизация компонентов в Compose делалась через параметры Composable функции (color = ..., padding = ...) или модификаторы. Это работало, но могло приводить к:
👉 избыточным рекомпозициям при смене состояний;
👉 дублированию кода для разных вариаций кнопок/карточек;
👉 сложностям с анимацией переходов между стилями.

Google представил Styles API (экспериментальный, о причинах такого статуса ниже) — новый подход, вдохновлённый CSS. Нужен Jetpack Compose 1.11.0 или свежее

Ключевые возможности
1️⃣ Производительность
Стили вычисляются на этапах layout и drawing, минуя composition. Это значит, что изменение стиля (например, при наведении) не вызывает рекомпозицию родительских компонентов.

2️⃣ Работа с состояниями
Без кучи if/else и animate*AsState. Просто описываете стиль для каждого состояния (нажат, сфокусирован, включён, ошибка и т.д.).

3️⃣ Встроенные анимации
Переходы между состояниями анимируются автоматически с физическими параметрами (демпфирование, жёсткость). Не нужно писать Animatable или Transition.

// Пример использования стиля
// Определяем стиль для кнопки
val buttonStyle = Style {
default {
backgroundColor = Color.Blue
shape = RoundedCornerShape(8.dp)
}
pressed {
backgroundColor = Color.DarkBlue
scale = 0.98f
}
disabled {
backgroundColor = Color.Gray
alpha = 0.5f
}
}

// Используем
Button(
onClick = { /* ... */ },
style = buttonStyle, // ← вместо кучи параметров
enabled = isEnabled
) {
Text("Нажми меня")
}


style — новый параметр, который появляется у всех компонентов Material 3 и базовых (Box, Row, Column).

⚠️ Styles API не заменяет модификаторы
Модификаторы остаются для позиционирования, кликов, размеров. Styles API заменяет только внутреннюю стилизацию (цвета, формы, тени, отступы внутри компонента). Это как разделение «темы» и «вёрстки».

API остаётся экспериментальным пока на него полностью не перейдет Material 3 Compose, чтобы учесть все необходиcмоти API и не делать breaking changes. По работе оно уже стабильно, но вот изменения в коде, возможно, будут.

🔗 Официальная документация

В целом с таким подходом уже привыкли работать в Android XML Layout, то почему бы сразу было его не использовать? Тем более в Compose плюсы очевидны!

💬 Пробовали уже играться со Styles API? Как вам идея отделить стили от композиции? Делитесь мнениями в комментариях 👇

#Compose #Material
Please open Telegram to view this post
VIEW IN TELEGRAM
🏝 HyperKey - Kotlin DSL для работы с ноткеями в Compose на Android и Desktop (чего iPadOS забыли)

HotKeyBox(
hotkeys = {
Key.S + Ctrl press { save() }
Key.K + Ctrl andThen Key.P press { openCommandPalette() }
Key.Space + Hyper press { spotlight() }
}
) {
MyApp()
}


#Kotlin #Android #Desktop
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Android Good Reads
This media is not supported in your browser
VIEW IN TELEGRAM
Compose анимации без пересборки

Дебажить анимации трудно и долго. Hot reload помогает и тут. Внутри анимация Grid, кастомная анимация волны на Canvas, изменение типа анимации tween -> spring, изменение animateContentSize
HotSwan обновляет примитивы в обход компиляции Gradle, за счет этого и получается такой результат
Forwarded from Android Broadcast
🤯 Те кто использовал Jetpack Paging 3 знают насколько он может справиться только с базовыми сценариямми. Шаг влево или вправо - уже боль!

Сегодня хочу познакомить вас с альтернативой — библиотекой 🐱 Paginator. Это KMP-решение для пагинации, которое решает те самые проблемы, где Paging 3 начинает "буксовать".

Paginator построен на отличной модели от Jetpack Paging 3: страница — это адресуемая ячейка в кэше, кэш — обычная структура данных, а навигация — обычные методы.

1️⃣ Адресуемые страницы
Прямые методы goNextPage(), goPreviousPage() и jump(Bookmark). Deeplink на сообщение из пуша решается одной строкой.

2️⃣ Мутации по запросу
MutablePaginator предоставляет CRUD-операции: replace { it.id == 42 }, removeWhere { it.deleted }. Один лайк меняет один элемент без инвалидации всей страницы.

3️⃣ Сохраняемое состояние
Кэш — обычная структура данных, которую можно сериализовать через kotlinx.serialization. Методы serializeToJson() и restoreFromJson() решают проблему Process Death без плясок с бубном.

4️⃣ Библиотека, а не фреймворк
Написан на чистом Kotlin без платформенных зависимостей и живёт в commonMain. Логика пагинации становится частью общего доменного слоя KMP, не копируется между платформами и не имеет двух реализаций.

5️⃣ Курсорная пагинация "из коробки"
Отдельный класс CursorPaginator с единой моделью состояний, транзакций и сериализации.

Paginator — это не обёртка над Paging 3. Это другая модель, переосмысливающая ключевые типы. Обёртка просто не смогла бы дать ни мутации элемента, ни сериализации кэша.


🔗 Оригинальная статья на Хабре
🐱 Репозиторий Paginator

#Android #AndroidDev #KMP
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Android Broadcast
🐘 В мире Android и тем более KMP проектов огромное количество зависимостей. Та самая ситуация, когда build зеленый, sync прошел, но приложение падает в рантайме из-за NoSuchMethodError или ClassNotFoundException, знакома многим. Причина — тихий конфликт версий. Gradle по умолчанию старается брать самую новую версию из всех найденных, но срабатывает не всегда. В разных модулях одного проекта могут спокойно жить разные версии одной библиотеки (например, okhttp 4.9.0 в модуле А и 4.11.0 в модуле Б). Gradle не считает это конфликтом, потому что модули изолированы. В рантайме при передаче объекта между модулями — ClassCastException. Особенно больно это бьет в KMP, где общая бизнес-логика связывает всё в единую цепочку.

Плагин 🐱 Dependency Conflict Analyzer переворачивает подход. Он встраивается в Gradle и каждый раз при синхронизации автоматически анализирует весь граф зависимостей по всем модулям. Не нужно ничего запускать вручную или гадать, кто что подтянул. Если есть расхождение в major-версиях — плагин сразу покажет конфликт в консоли. Причём он найдет даже скрытые расхождения между разными модулями, которые Gradle игнорирует.

# Пример работы плагина
Version conflict detected: org.slf4j:slf4j-api
- version 2.0.17 via:
- project :app -> ch.qos.logback:logback-classic:1.4.11 -> org.slf4j:slf4j-api:2.0.17
...
- version 1.7.25 via:
- project :app -> org.apache.logging.log4j:log4j-slf4j-impl:2.17.1 -> org.slf4j:slf4j-api:1.7.25


Такая проактивная проверка помогает фиксить конфликты еще на этапе разработки и писать более стабильный код. Попробуйте.

#Gradle
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Android Broadcast
🤖 GPT 5.5 и 5.4 лучше подходят для Android разработки, чем модели Claude. РАУНД!

Данные официального бенчмарка Google

#AI #Benchmark
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Android Good Reads
Android CLI зацикливает на себе весь цикл разработки для андроид c агентами. Вам не нужно прыгать и искать какие скилы подтянуть в проект, какой контекст по андроид разработке предоставить. All-in-one от гугла (sdk, эмуляторы, запуск билдов ... )

Ни для чего другого, кроме как мобильной разработке, это не подходит, так что поставить точно рекомендую!
This media is not supported in your browser
VIEW IN TELEGRAM
Все идет по пути к тому что у каждого тула будет CLI версия. Обсидиан запустил пару месяцев назад, а вот и Google (Пере)представляет Android CLI

По ощущениям оч кастрированный и является надстройкой над adb

(c) Антоха Разраб про AI
Forwarded from Android Good Reads
Если вы используете Metro, в качестве DI, то знайте что оно стало стабильным. Свеженаписанный легковесный DI для android

Релиз ноутс: https://github.com/ZacSweers/metro/releases/tag/1.0.0
Forwarded from Android Good Reads
Что нового в Compose в Апреле

compose-bom:2026.04.01 или Compose 1.11.0
👉 v2 API тестирования стал дефолтным, StandardTestDispatcher вместо UnconfinedTestDispatcher. Коррутины в тестах больше не выполняются сразу — очередь, пока виртуальные часы не продвинутся
👉 Shared Elements: новый composable LookaheadAnimationVisualDebugging показывает границы анимаций, траектории и несовпадения
👉 Поддержка трекпадов: теперь трекпады распознаются как PointerType.Mouse, а не Touch. Исправляет скролл вместо выделения, добавляет поддержку жестов и десктопных контекстных меню
👉 Compose runtime: новый HostDefaultProvider позволяет библиотекам (особенно KMP) получать сервисы без зависимости от compose-ui
👉 Аннотация @PreviewWrapper для переиспользуемых обёрток превью:
class ThemeWrapper: PreviewWrapper {
@Composable
override fun Wrap(content: @Composable (() -> Unit)) {
JetsnackTheme {
content()
}
}
}

@PreviewWrapperProvider(ThemeWrapper::class)
@Preview
@Composable
private fun ButtonPreview() {
// JetsnackTheme in effect
}

👉 Готовимся что в 1.12.0 compileSdk обновится до 37. Будет много боли потому что 37 Sdk тянет за собой AGP 9

Android Good Reads
Forwarded from Android Good Reads
Что нового в Compose в Апреле Часть 2

Экспериментальные API:

👉 Styles API: декларативные стили компонентов с автоматическими анимациями. Судя по бенчмаркам, быстрее модификаторов
👉 MediaQuery: адаптация под окружение (размер окна, тип клавиатуры, режим стола и т.д.)
👉 Grid: 2D-раскладка с треками, фракциями (fr) и авто-размерами
👉 FlexBox: мощный контейнер с гибким распределением пространства, wrap'ом и выравниванием. Замена Row/Column/Flow
👉 Новый SlotTable: ускорение случайных правок в дереве композиции (пока опционально через флаг)

Android Good Reads
Forwarded from Compose Broadcast
⚙️ Compose 1.11: Composition host defaults — мелочь, важная для KMP

В апрельском релизе Jetpack Compose под номером 1.11 в compose-runtime завезли четыре новых API: HostDefaultProvider, LocalHostDefaultProvider, HostDefaultKey и ViewTreeHostDefaultKey. Плюс билдер compositionLocalWithHostDefaultOf для авторов библиотек.

Он позволяют объявить CompositionLocal, у которого дефолтное значение резолвится из окружения хоста — например, через Android View tag'и (как это делает ViewTreeLifecycleOwner или ViewTreeOnBackPressedDispatcherOwner). Раньше для такого паттерна была обязательна зависимость на compose-ui. Теперь только compose-runtime.

Раньше чтобы из библиотеки достать значение из View tree, приходилось тянуть compose-ui ради LocalView и платформенные функции поиска по дереву View. Код жил в Android-сорсах, в commonMain такое не положишь:
    // androidMain — compose-ui + Android-only API
val LocalMyOwner = compositionLocalOf<MyOwner?> { null }

@Composable
fun ProvideMyOwner(content: @Composable () -> Unit) {
val view = LocalView.current
val owner = remember(view) {
view.findViewTreeMyOwner()
}
CompositionLocalProvider(LocalMyOwner provides owner) {
content()
}
}


С новым API описание CompositionLocal живёт в commonMain и тянет только compose-runtime. Связку с View tree описывает ViewTreeHostDefaultKey, и хост сам отдаёт значение через своего провайдера:

    // commonMain — только compose-runtime
val MyOwnerKey = ViewTreeHostDefaultKey<MyOwner>(
viewTagId = R.id.view_tree_my_owner
)

val LocalMyOwner = compositionLocalWithHostDefaultOf(MyOwnerKey)

// Использование — без изменений
@Composable
fun MyComponent() {
val owner = LocalMyOwner.current
// ...
}


Теперь авторы Compose библиотек могут держать определение CompositionLocal в общем модуле без зависимости на compose-ui. Профит - меньше транзитивных зависимостей в KMP-библиотеках и более чистое разделение слоёв runtime и UI.

#Compose #CMP
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Compose Broadcast
⚙️ Compose Multiplatform 1.11.0 вышел

Главные фичи:
1️⃣ Нативный text input на iOS через UIView, UITextInput и UIKeyInput (экспериментально)
2️⃣ v2 API для Compose UI-тестов на не-Android таргетах
3️⃣ Переписанный с нуля скроллинг на Web

Breaking изменения, которые заденут почти всех:
👉 Минималка Kotlin поднята до 2.3.10
👉 Минимальная iOS теперь 14 (поддержка 13 ушла)
👉 iosX64 и macosX64 удалены полностью
👉 Shader на не-Android стал wrapper-классом

Я ждал нативный input на iOS с того момента, как Compose туда заехал. Текущая реализация на Skia всегда чувствовалась чужой на ощупь, особенно при сложном выделении и системных меню. Надо пробовать!

#compose #cmp #kotlin
Please open Telegram to view this post
VIEW IN TELEGRAM
👨‍💻 Опенсорсим yx_navigation — декларативную навигацию для Flutter

Навигация во Flutter сначала кажется автору простой: push и pop. Но по мере роста проекта появляются табы, вложенные модули, диплинки — и каждый экран начинает открываться по-своему, а pop() ведёт себя непредсказуемо.

Navigator 1.0 прост, но не масштабируется. Navigator 2.0 даёт контроль, но требует тонны бойлерплейта. Пакеты вроде go_router (режим поддержки) и auto_route (кодогенерация) решают часть проблем, но не все.

Автор и его команда прошли через все эти варианты в Яндекс Про — приложении с сотнями фич, несколькими командами и вложенной навигацией. Так появился yx_navigation — новый пакет в экосистеме архитектурных решений для Flutter, следующий после yx_scope (DI) и yx_state (управление состоянием).

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

👉 Читать статью

📌 Лучшие вакансии для мобильных разработчиков

🐸 Библиотека мобильного разработчика

#свежак #Flutter
Please open Telegram to view this post
VIEW IN TELEGRAM
🏝 JetBrains обновили дефолтную структуру KMP проектов. Теперь общий код живёт в shared модуле, а под каждую целевую платформу свой отдельный application модуль.

Раньше всё было в одном composeApp, который одновременно был и KMP библиотекой, и приложением. Это создавало путаницу в build конфигах и платформенных настройках. iOS при этом уже жил в отдельной папке, и асимметрия торчала наружу.

Главным триггером изменений стал Android Gradle Plugin 9, который больше не позволяет применять Android application plugin к multiplatform модулю. Entry point Android приложения теперь обязательно вынесен в отдельный модуль.

Если в проекте есть нативный UI (например, SwiftUI для iOS), shared разбивается на два модуля: sharedLogic без Compose зависимостей и sharedUI только для платформ с Compose Multiplatform. Для проектов с серверной частью добавляется server модуль и core с общими моделями и валидацией для шаринга между клиентом и сервером.

Я ещё до этого держал каждый application в отдельном модуле, так что для меня новая дефолтная структура лишь оформляет то что уже стало здравым смыслом. Раньше с одним shared было неприятно из-за того что Kotlin stdlib и зависимости тащились в каждый iOS framework. Несколько атомарных shared модулей решают эту проблему и позволяют точечнее управлять тем что попадает на каждую платформу. Очень рад что JetBrains двигаются в сторону более атомарных модулей, но пока есть вопросы не будет ли дублирования базовых Kotlin библиотека в каждый Xcode фреймворк.

Новая структура уже доступна в KMP wizard на kmp.new и в IDE плагине.

🔗 Анонс
📹 Видео разбор от JetBrains

#Kotlin #KMP #Gradle
Please open Telegram to view this post
VIEW IN TELEGRAM
Forwarded from Android Broadcast
‼️ Android View всё! Да здравствует Compose!

Google официально объявила о переходе к стратегии «Compose-first» и прекращении развития Android View, переводя его в режим поддержки.

Что это значит:
👉 Классы android.widget.* в Android SDK будут находиться в режиме поддержки.
👉 Библиотеки Android Jetpack про кастомные View (включая RecyclerView) также переходят в режим поддержки.
👉 Все инструменты в Android Studio будут создаваться только для Compose.
👉 Документация будет писаться только для Compose, однако некоторые разделы про View останутся.

🔗 Источник - оф сайт Android Developers

#Android #AndroidDev #Compose
Forwarded from Android Broadcast
⚰️ Полный список Jetpack библиотек которые перешил в Maintain режим:
👉 CardView
👉 ConstraintLayout
👉 CoordinatorLayout
👉 CustomView
👉 Databinding
👉 DragAndDrop
👉 DrawerLayout
👉 DynamicAnimation
👉 Emoji
👉 Fragment
👉 GridLayout
👉 Interpolator
👉 Loader
👉 Navigation
👉 PercentLayout
👉 Preference
👉 RecyclerView
👉 SlidingPaneLayout
👉 SwipeRefreshLayout
👉 Transition
👉 VectorDrawable
👉 ViewPager
👉 ViewPager2
👉 Material Design Components (Views)

Считаю что делать так с RecyclerView поступили опрометчиво, ведь не все возможности может сделать Lazy*** Composable, а вот на Fragment и подавно куча приложений строится. Но нам дадут волшебные скиллы для миграции по одному экрану за раз

#Android #AndroidDev #Compose #
Please open Telegram to view this post
VIEW IN TELEGRAM