en
Feedback

Don't get caught by a cheater! Telemetrio finds and tags such channels 👉 If you want to see the tag, subscribe

Compose Broadcast

Compose Broadcast

Open in Telegram

Все о Jetpack Compose и Compose Multiplatform По сотрудничеству - @ab_manager

Show more
5 884
Subscribers
-224 hours
-127 days
-930 days
Posts Archive
⚙️ Styles API в Compose переделывают: документацию временно убрали На Google I/O команда Compose показала Styles, новый способ настраивать внешний вид компонентов. Теперь она сообщила, что по итогам отзывов API станет менее навязчивым: определения визуальных свойств переедут из слоя foundation в слой дизайн-системы, то есть в Material или вашу собственную. Дизайн-система сама решит, какие свойства её компонентов можно стилизовать, а свои свойства можно будет объявлять через stylePropertyOf и styleLocalOf. Пока идёт переделка, с developer.android.com сняли весь раздел про Styles (основы, темизацию, анимации состояний, сравнение с Modifier, рекомендации и ограничения), а также опубликованный ранее скилл для AI-агентов. В Compose 1.13 Styles API остаётся @Experimental.
⚠️ Если вы уже пробовали Styles в коде, API ещё поменяется. Новую форму обещают показать отдельно и собрать по ней отзывы.
🔗 Styles update #Compose #JetpackCompose #Android

CmpDevicePreview от Apadmi рисует приложение на Compose Multiplatform в рамке устройства. Рядом панель, в которой переключаются модель, ориентация, тёмная тема, размер текста, язык и клавиатура. Работает на Android, iOS, macOS, Desktop, JS и Wasm, поэтому веб-демо приложения можно выложить в интернет.
implementation("com.apadmi:cmpdevicepreview:0.1.0")

DeviceWithConfigurationView {
    App()
}
Insets, isSystemInDarkTheme(), font scale и window size classes внутри рамки берутся от симулированного устройства, так что менять код приложения не нужно. В вебе настройки попадают в URL, и превью можно отправить ссылкой.
⚠️ На Android нельзя подменить insets и тёмную тему хоста, а диалоги выходят за рамку. Версия 0.1.0, API ещё меняется.
🔗 GitHub · Live demo #Compose #ComposeMultiplatform #KMP #Kotlin

⚙️ ComposeStateMonitor: лог объясняет, почему composable перерисовался Экран дёргается, Layout Inspector показывает растущий счётчик рекомпозиций, но не говорит главного: какой параметр или стейт её вызвал. ComposeStateMonitor отвечает как раз на этот вопрос. Вы вешаете на функцию @ComposableMonitor, плагин компилятора дописывает в неё отслеживание параметров и State-переменных, и при каждой рекомпозиции в лог падает строка:
CounterLabel recomposed because
    `count` changed from `0` to `1`
Работает на всех таргетах Compose Multiplatform: Android, desktop, iOS, wasmJs и js. Нужны Kotlin 2.0+ (под каждую линию 2.0–2.4 своя сборка плагина), Gradle 7.6+ и Compose 1.6.11+. На Android по умолчанию инструментируется только debug, на остальных платформах мониторинг лучше включать Gradle-свойством. Идея и трекер изменений взяты из Rebugger, но здесь не нужно вручную перечислять, что отслеживать.
⚠️ Проект совсем свежий: репозиторий появился 22 октября, версия 0.2.0. Лямбды, локальные функции и стейт во вложенных блоках пока не отслеживаются.
🔗 GitHub #Compose #CMP #KMP #Android

⚙️ Прогрессивный blur в Compose: Google выпустил гайд по новым API из 1.13 До сих пор Modifier.blur умел одно: размыть композабл целиком с одинаковым радиусом. Чтобы края списка мягко уходили в размытие, приходилось писать свой шейдер или брать библиотеку вроде Haze. В Compose UI 1.13.0-beta01 появились BlurRadiusSpec и BlurStop, и теперь в документации есть гайд и готовые рецепты. Радиус теперь меняется по поверхности: градиентом сверху вниз, слева направо, по линии или от точки. Например, так края списка размываются, а центр остаётся чётким:
LazyColumn(
    modifier = Modifier.blur(
        blurRadiusSpec = BlurRadiusSpec.verticalGradient(
            stops = listOf(
                BlurStop(fraction = 0f, radius = 18.dp),
                BlurStop(fraction = 0.42f, radius = 0.dp),
                BlurStop(fraction = 0.58f, radius = 0.dp),
                BlurStop(fraction = 1f, radius = 18.dp),
            ),
        ),
        edgeTreatment = BlurredEdgeTreatment.Unbounded,
    ),
) { /* ... */ }
⚠️ Modifier.blur размывает то, что рисует сам композабл. Размытие фона под панелью (backdrop blur) гайд не покрывает, а переменный радиус ограничен 150 px.
🔗 Гайд · Примеры #Compose #JetpackCompose #Android

⚙️ Дизайн-система как контракт: Konsist и Lint не дают обойти её в Compose Дизайн-система есть почти у каждой команды, но чер
⚙️ Дизайн-система как контракт: Konsist и Lint не дают обойти её в Compose Дизайн-система есть почти у каждой команды, но через пару месяцев на одном экране отступ 16.dp, на другом 18.dp, где-то свой TextStyle и захардкоженный hex-цвет. Ревью всё не ловит. Ravi Rawal предлагает считать дизайн-систему инженерным контрактом и проверять его автоматически. Konsist следит за архитектурой: фичи не должны зависеть от внутренностей дизайн-системы.
Konsist.scopeFromProject().assertArchitecture {
    val features = Layer("Features", "com.acme.feature..")
    val dsInternal = Layer("DS Internal", "com.acme.designsystem.internal..")
    features.doesNotDependOn(dsInternal)
}
Но Color(0xFF1769E0) прямо в фиче такой тест пропустит. Здесь нужен свой Lint-детектор, а UI-тесты проверяют то, что видно только в рантайме.
⚠️ Детектор из статьи — стартовый: Color.Red или цвет из константы он не поймает.
🔗 Статья · Konsist #Compose #JetpackCompose #Android #Konsist

🐱 nav3-uikit: Navigation 3 в CMP с настоящим UINavigationController на iOS Автор nav3-uikit предлагает простую сделку: переименуйте NavDisplay в NativeNavDisplay, и экраны Compose Multiplatform на iOS окажутся внутри настоящего UINavigationController. Кнопка «Назад», свайп от края и меню истории — уже не имитация, а сам UIKit.
NativeNavDisplay(
    backStack = backStack,
    onBack = { backStack.removeLastOrNull() },
    entryProvider = entryProvider {
        entry<Home>(metadata = NativeNavigation.title("Home", large = true)) { HomeScreen() }
    },
)
Каждый экран — отдельный ComposeUIViewController, а через metadata можно включить large title или открыть экран как нативный sheet. Для вкладок есть NativeTabDisplay с UITabBarController. Источником правды остаётся ваш back stack: системный pop вызывает onBack, а если приложение его отклонит, экран вернётся на место. На Android и десктопе всё работает через обычный NavDisplay.
⚠️ Проект экспериментальный: версия 0.1.0-dev01, репозиторий создан 16 октября. Нативные вкладки требуют iOS 18+.
🔗 GitHub · Как это устроено #Compose #CMP #Navigation3 #iOS

Repost from AI Dev Broadcast
⚙️ Spyglass: агент наконец видит Compose UI, который сам написал Агент может написать экран на Compose, который компилируется, но не видит, что отступ съехал, текст обрезан, а кнопка не того цвета. Это выясняется, только когда вы откроете IDE. Spyglass закрывает этот пробел: рендерит @Preview в PNG без IDE, эмулятора и устройства и сравнивает результат с макетом. В ответ агент получает процент совпадения, список отличающихся областей в px и dp и тепловую карту. Дальше он сам правит код и сравнивает снова. В демо так нашлась даже ошибка в одной букве: «Priority Support» вместо «Priority support». Работает из командной строки, в CI и как MCP-сервер для Claude и других агентов. Билд-файлы трогать не надо: CLI запускает ваш gradlew со своим init-скриптом только на время рендера.
⚠️ Проект на ранней стадии (0.1.0, появился 15 октября): сейчас рендерятся превью из commonMain и desktop-кода Compose Multiplatform, Android-only превью пока только в планах.
🔗 GitHub · Релиз #AI #MCP #Compose #KMP

⚙️ Compose → PDF: счёт можно сверстать composable-функцией В начале октября в kotlinlang #compose спросили: как на сервере отрендерить Compose UI в PDF, например для генерации счетов? На Android есть PDF API с Canvas, а на JVM? Через ImageComposeScene получится только картинка внутри PDF, без векторного текста. Skia умеет писать PDF сама, но в Skiko эта поддержка так и не появилась (SKIKO-1017). Автор вопроса в итоге остановился на готовой библиотеке compose2pdf. compose2pdf работает на Compose Desktop: перехватывает отрисовку через SVGCanvas Skia и переводит её в PDF через PDFBox. Текст остаётся выделяемым, шрифты встраиваются, страницы разбиваются автоматически, а результат можно стримить прямо из Ktor.
val pdf = renderToPdf(config = PdfPageConfig.A4WithMargins) {
    Text("Invoice #1234", fontSize = 24.sp, fontWeight = FontWeight.Bold)
    Text("Amount: $1,250.00")
}
Если PDF нужен и в мобильном приложении, есть compose-multiplatform-pdf-export для Android, iOS и JVM: на Android он пишет через PdfDocument, на iOS — в PDF-контекст CoreGraphics.
⚠️ compose2pdf — только JVM, Android и iOS он не поддерживает. Обе библиотеки сторонние и появились в этом году.
🔗 Обсуждение · compose2pdf · compose-multiplatform-pdf-export #Compose #CMP #KMP #PDF

🐱 compose-desktop-native: Compose Desktop без JVM, одним нативным бинарником Compose Desktop работает только на JVM, поэтому даже маленькая утилита едет к пользователю вместе с Java. Автор compose-desktop-native пошёл другим путём: собрал Compose на Kotlin/Native, а окна, ввод, звук, диалоги и буфер обмена отдал SDL3. На выходе получается один исполняемый файл для macOS, Linux или Windows, без JVM. Compose при этом не переписан: runtime берётся официальный, а ui, foundation и material3 скопированы из Compose Multiplatform как есть. Рисует всё тот же Skia.
fun main() = nativeComposeWindow(title = "Hello") {
    Text("Hello from Compose Desktop Native")
}
В свой проект его подключают Gradle-плагином: вы объявляете обычные зависимости Compose, а плагин подменяет их на порт только для нативных desktop-таргетов. Android, JVM, iOS и Web продолжают собираться на официальных артефактах.
⚠️ Это сторонний проект, а не JetBrains: артефакты — форк com.bitsycore, на Windows используется форк Skiko. Репозиторию четыре месяца.
🔗 GitHub · Пример с плагином #Compose #CMP #KotlinNative #Desktop

⚙️ Свой rich text редактор на TextField: Google выпустил подробный гайд В августе Compose Foundation 1.12 научил TextFieldState хранить SpanStyle и ParagraphStyle вместе с текстом. Но как сделать кнопку «жирный», которая работает с выделением и не ломается при правках, приходилось разбираться самим. Теперь в документации есть отдельный гайд, а полная реализация лежит в сэмпле Jetchat. Ключевая настройка — ExpandPolicy: она решает, подхватит ли стиль текст, напечатанный ровно на его границе. AtEnd ведёт себя как обычный редактор, InsideOnly подходит для @упоминаний, которые не должны «расползаться».
state.edit {
    addStyle(
        spanStyle = SpanStyle(fontWeight = FontWeight.Bold),
        range = selection,
        expandPolicy = ExpandPolicy.AtEnd
    )
}
addStyle возвращает TrackedRange, который сам сдвигается при правках и живёт только внутри edit. Для тулбара и сериализации есть TextFieldState.textStyles. 🔗 Гайд · Jetchat #Compose #JetpackCompose #Android

🧭 Навигация из Android-приложения переезжает в общий код Compose Multiplatform В JetBrains напомнили Android-разработчикам: знакомые NavController и NavHost можно вынести в общий код и получить одну модель навигации с типобезопасными маршрутами, одним графом и одним стеком экранов на Android, iOS, десктопе и в вебе. Всё это собрано в разделе документации Kotlin Multiplatform «Navigation in Compose». Мультиплатформенную поддержку в библиотеку AndroidX Navigation добавляет команда Compose Multiplatform, поэтому подход тот же, что на Android: маршрут — сериализуемый объект или data class с аргументами, а граф описывается внутри NavHost:
@Serializable
object Profile
@Serializable
object FriendsList

val navController = rememberNavController()

NavHost(navController = navController, startDestination = Profile) {
    composable<Profile> { ProfileScreen( /* ... */ ) }
    composable<FriendsList> { FriendsListScreen( /* ... */ ) }
}
Подключается всё одной зависимостью org.jetbrains.androidx.navigation:navigation-compose в commonMain. Жест «назад» библиотека переводит в возврат на предыдущий экран на каждой платформе: на iOS это свайп, на десктопе — клавиша Esc. Для iOS по умолчанию включена анимация перехода в духе нативной, но если задать свои enterTransition или exitTransition, она отключится. Выключить обработку жеста на iOS можно флагом enableBackGesture = false в ComposeUIViewController.
⚠️ Диплинки по умолчанию не видны внешним приложениям: URI-схему нужно отдельно зарегистрировать в каждой целевой ОС. А если на iOS нужны системные эффекты вроде Liquid Glass в навигационном интерфейсе, документация советует перенести навигацию в нативный SwiftUI и оставить Compose для содержимого экранов.
🔗 Navigation in Compose · пост Kotlin #Compose #ComposeMultiplatform #Kotlin #Navigation

🧭 В рецептах Navigation 3 для модульного приложения появились диплинки Google переписал гайды Modular with Hilt и Modular wi
🧭 В рецептах Navigation 3 для модульного приложения появились диплинки Google переписал гайды Modular with Hilt и Modular with Koin: каждый feature-модуль теперь регистрирует не только свои экраны, но и сопоставитель (matcher) для диплинка. Вот как это делает модуль профиля в варианте с Hilt:
@IntoSet
@Provides
fun provideDeepLinkMatcher(): BackStackMatcher<*, NavKey> =
    UriDeepLinkMatcher(
        uriPattern = DeepLinkUri(PROFILE_URI),
        serializer = Profile.serializer(),
    ).withBackStack { matchResult ->
        listOf(ConversationList, matchResult.key)
    }
Navigator.handleDeepLink(intent) в модуле common перебирает все такие сопоставители и по URI собирает искусственный стек экранов, а для обычного запуска и запуска по диплинку в примерах заведены отдельные Activity. Так фичу можно открыть по ссылке, не зная, как устроена навигация в соседних модулях. 🔗 Hilt · Koin #Compose #Navigation3 #AndroidDev

⚙️ Вышел Compose Multiplatform 1.12.2 Патч к 1.12.1 без новых фич — три точечных фикса. Gradle-плагин и библиотеки: org.jetbr
⚙️ Вышел Compose Multiplatform 1.12.2 Патч к 1.12.1 без новых фич — три точечных фикса. Gradle-плагин и библиотеки: org.jetbrains.compose:1.12.2. 👉 Multiple platforms: убрали мигание при анимации непрямоугольных graphicsLayer-теней (#3465) 👉 iOS: краш, когда TextField терял фокус из‑за показанного Dialog (#3459) 👉 Web: поведение фокуса backing text input под iOS Safari 27.0 (#3466) Material3 в этом релизе по‑прежнему на 1.12.0-alpha03, Navigation3 — 1.2.0-rc01. Имеет смысл обновиться, если ловили эти баги. 🔗 Release notes 1.12.2 #Compose #CMP #KMP

⚙️ Compose Foundation 1.13: TextField с value/onValueChange уходит в deprecated В 1.13.0-alpha03 (сейчас уже beta01) BasicTex
⚙️ Compose Foundation 1.13: TextField с value/onValueChange уходит в deprecated В 1.13.0-alpha03 (сейчас уже beta01) BasicTextField(value, onValueChange) и такие же перегрузки Material 2 TextField помечены deprecated. Замена — state-based API на TextFieldState. 👉 Маски: VisualTransformation тоже deprecated, переходите на OutputTransformation. Пишете insert(4, "-"), а offset mapping считается автоматически 👉 Фильтрация переезжает из onValueChange в InputTransformation. maxLength deprecated: вместо него maxLengthTrim (обрезает) и maxLengthReject (отклоняет ввод) 👉 ViewModel: держать TextFieldState во ViewModel нормально, но отдельно от UiState 👉 Кому и когда: всем, у кого есть формы. Пока это только предупреждения компилятора, код собирается. Мигрировать лучше заранее, особенно маски и StateFlow-формы
// было
TextField(value = text, onValueChange = { text = it })
// стало
TextField(state = rememberTextFieldState())
🔗 Гайд по миграции 🔗 Release notes #Compose #JetpackCompose #Android

ИИ помогает писать код для Android — но как проверить, что он действительно работает? 🚀 21 октября в 20:00 МСК — открытый ве
ИИ помогает писать код для Android — но как проверить, что он действительно работает? 🚀 21 октября в 20:00 МСК — открытый вебинар "Написание текстов для Android в эпоху ИИ" 👨🏻‍💻 На вебинаре курса «Android-разработчик. Продвинутый уровень»: • разберём пирамиду тестирования и соотношение уровней проверок; • пройдёмся по модульным и интеграционным тестам, тестам интерфейса, проверкам по снимкам экрана и архитектурным тестам; • для каждого вида обсудим пользу для проекта и случаи, когда его стоит применять; • отдельно — почему эти проверки нужны при работе с ИИ и как выбирать тесты для Android-приложения. 🧩 После урока вы: — увидите тестирование как систему, а не набор разрозненных практик; — поймёте назначение разных видов проверок; — сможете выбирать подходящие тесты под свою задачу; — начнёте системнее проверять код в своих проектах. Спикер: Максим Качинкин. 👉 Регистрация на открытый вебинар: тут Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576

⚙️ Скилл по аудиту производительности Compose опубликовали. Доступен через Android CLI #Compose #AndroidDev #AI

⚙️ Скилл по аудиту производительности Compose опубликовали. Доступен через Android CLI #Compose #AndroidDev #AI

Mobile вызывает. Ответите? 📱 VK JT Mobile Meetup на связи сразу в двух городах: 📍 В Москве — 31 октября 📍 В Санкт-Петербур
Mobile вызывает. Ответите? 📱 VK JT Mobile Meetup на связи сразу в двух городах: 📍 В Москве — 31 октября 📍 В Санкт-Петербурге — 14 ноября В Москве вас ждут два параллельных трека — iOS и Android, а в Петербурге — один общий мобайл-трек. На проводе будут инженеры ВКонтакте, Дзена, MAX, VK Tech и других команд ВК. В программе — реальные кейсы мобильной разработки: 120 FPS, анализ влияния, сравнительные тесты, ИИ, архитектура и другие задачи производства. После докладов можно обсудить кейсы с другими разработчиками, поучаствовать в интерактивах и пообщаться на вечеринке. Мероприятие рассчитано на iOS- и Android-разработчиков и пройдут только офлайн. Принимайте вызов в своём городе! → Регистрация #реклама

⚙️ Google переписал гайд по стабильности в Compose: часть старых советов теперь наоборот Старая версия писала, что нестабильн
⚙️ Google переписал гайд по стабильности в Compose: часть старых советов теперь наоборот Старая версия писала, что нестабильный параметр значит рекомпозицию всегда. Но с Kotlin 2.0.20 по умолчанию работает Strong Skipping, и нестабильные параметры сравниваются по ссылке (===). Гайд наконец под это обновили, и советы поменялись. 👉 Коллекции. Раньше советовали Kotlinx immutable collections или @Immutable/@Stable. Теперь: не делайте этого без нужды в equals(). === стоит O(1), а equals() по большому списку на каждой рекомпозиции может выйти дороже самой рекомпозиции 👉 Типы из других модулей. Вместо обёрток в UI-модели теперь файл конфигурации стабильности или аннотации, но только для небольших моделей с дешёвым equals() 👉 Отладка. Первым делом проверьте, не создаётся ли новый экземпляр нестабильного параметра на каждой рекомпозиции 🔗 Stability in Compose #Compose #AndroidDev #Performance