Новости о продуктах

Что нового в релизе Jetpack Compose от августа 2026 года?

5 минут чтения
Посмотреть профиль Ника Бутчера
Nick Butcher менеджер по продуктам

Сегодня вышел стабильный релиз Jetpack Compose от августа 2026 года! В этом релизе представлена ​​версия 1.12 для основных модулей Compose (см. полное сопоставление BOM ), добавлены расширенные визуальные API, такие как градиенты сетки и поддержка широкого цветового охвата (WCG), структурные функции компоновки, например, именованные области в Grid , бесшовная интеграция с менеджером учетных данных Android, а также значительные улучшения в тестировании и производительности.

Чтобы обновить ваш проект до текущей версии, обновите версию Compose BOM до 2026.08.00 :

implementation(platform("androidx.compose:compose-bom:2026.08.00"))

Решающие перемены

  • AGP и Compile SDK : В Compose 1.12 обновлен compileSdk до API 37, что требует как минимум AGP 9.1.2. Напоминаем, что Compose всегда будет использовать последнюю версию compileSdk. Подробнее об этом изменении можно узнать здесь .
  • Modifier.onFirstVisible() устарел : следует перейти на Modifier.onVisibilityChanged() , который обеспечивает более точное отслеживание пороговых значений видимости.

Графика

Градиенты сетки

В Compose 1.12 появилась MeshGradientPainter , которая поможет вам создавать многоточечные, органичные цветовые градиенты.

meshGradient.gif
val rows = 1
val columns = 1

val gradientPainter = remember {
    MeshGradientPainter(rows, columns) {
        // Parameters: row, column, position, color
        setVertex(0, 0, Offset(0f, 0f), Color.Red)     // Top-Left
        setVertex(0, 1, Offset(1f, 0f), Color.Blue)    // Top-Right
        setVertex(1, 0, Offset(0f, 1f), Color.Green)   // Bottom-Left
        setVertex(1, 1, Offset(1f, 1f), Color.Yellow)  // Bottom-Right
    }
}

Box(
    modifier = modifier
        .aspectRatio(16/9f)
        .fillMaxWidth()
        .paint(gradientPainter)
)

Для получения дополнительной информации и примеров см. документацию .

Поддержка широкого цветового охвата и HDR

Современные дисплеи обеспечивают расширенную цветопередачу и более высокий динамический диапазон. В Compose 1.12 включена полная поддержка рендеринга с широким цветовым охватом (P3) и HDR для графики, отрисовки и шейдеров Compose. Цвета, определенные в цветовых пространствах, отличных от sRGB (например, Display P3), сохраняются до момента рендеринга на платформе без ограничения цвета. Цвета будут безопасно возвращаться к sRGB, если они используют неподдерживаемое цветовое пространство (например, CieXyz, CieLab или Oklab), зависят от цветового пространства неподдерживаемой версии Android (например, Bt2020Hlg на Android 13 и ниже) или если приложение работает на Android 9 (API 28) и ниже.

Другие заметные изменения:

  • В классы GraphicsLayer и Modifier.graphicsLayer добавлена LayerOutsets , позволяющая расширить визуальные границы слоя за пределы его измеренного размера. Применение LayerOutsets позволяет избежать неявного поведения clipToBounds при перемещении слоя в буфер за пределами экрана.

Стили

На конференции Google I/O мы поделились своим первоначальным видением API стилей Compose — единого, высокопроизводительного способа стилизации компонентов. С тех пор мы продолжаем развивать базовую архитектуру, гарантирующую строгую типобезопасность и предсказуемую корректность, а также поддержку создания пользовательских систем дизайна.

Чтобы обеспечить корректную работу этого базового уровня, API останется экспериментальным, и вы можете ожидать изменений, нарушающих обратную совместимость.

Оптимизация во время выполнения

Перегрузка побочных эффектов, связанных с ключом

SideEffect теперь поддерживает аргументы клавиш, что позволяет запускать одноразовые побочные эффекты при изменении определенных клавиш. Это может привести к повышению производительности по сравнению с использованием LaunchedEffect или DisposableEffect , если вам не нужна сопрограмма или блок освобождения ресурсов. SideEffect работает до 90% быстрее, чем LaunchedEffect , и примерно на 20% быстрее, чем DisposableEffect . Обратите внимание, что SideEffect запускает свой эффект до DisposableEffect и LaunchedEffect , поэтому будьте осторожны при переносе существующих эффектов на этот API, особенно для LaunchedEffects , которые полагаются на запуск после завершения текущего кадра.

@Composable
fun AnalyticsTracker(userId: String, screenName: String) {
    SideEffect(key1 = userId, key2 = screenName) {
        analytics.logScreenView(userId, screenName)
    }
}

Анимация

Интерактивные двухэтапные переходы

  • Новые компоненты : DeferredAnimatedContent и DeferredAnimatedVisibility позволяют создавать восхитительные двухэтапные переходы, например, для прогнозирующего отслеживания жестов при движении назад.
  • Ручное управление анимацией : Во время отложенной фазы перехода анимированные свойства (например, масштаб или смещение) теперь можно вручную изменять в режиме реального времени (например, отслеживать жест смахивания).
  • Бесперебойная передача управления : После завершения отложенной фазы механизм перехода берет на себя управление и осуществляет бесперебойную передачу управления, включая передачу скорости, автоматическому переходу.
  • Поддержка общих элементов : новый флаг permitTransformDuringDeferredTransition в SharedContentConfig определяет, будут ли общие элементы визуально трансформироваться вместе со своими родительскими контейнерами во время фазы отложенного перехода.
val state = remember { DeferredTransitionState(initialScreen) }
val transition = rememberDeferredTransition(state)

if (predictiveBackInProgress) {
    state.defer(targetScreen)
} else {
    state.animateTo(targetScreen)
}

transition.DeferredAnimatedContent(
    targetState = targetScreen,
    mutableTransformSpec = {
       MutableContentTransform {
           // Manually manipulate properties during the deferred phase
           initialContentTransform { scale = swipeProgress }
       }
    }
) { screen ->
    ScreenContent(screen)
}

Ниже представлены два примера использования, в которых анимация, управляемая жестами, передается анимации, запускаемой по триггеру:

colorCards.gif

Интеграция текста, ввода и платформ

Редактируемое форматирование текста

Новые API-интерфейсы предлагают форматирование редактируемого текста в BasicTextField . Теперь вы можете программно применять и изменять встроенное форматирование символов и абзацев с помощью SpanStyle и ParagraphStyle через новый метод addStyle() внутри области видимости TextFieldBuffer (например, внутри textFieldState.edit { ... } или InputTransformation ). Кроме того, TextFieldBuffer предоставляет API-интерфейсы getSpanStyles() и getParagraphStyles() , которые возвращают объекты TrackedRange , позволяющие читать, обновлять или удалять примененные стили. В дополнение к созданию форматирования, TextFieldState теперь предоставляет свойство textStyles только для чтения, позволяющее запрашивать активные стили в диапазонах, а TextFieldBuffer предоставляет originalTextStyles для проверки состояния форматирования перед редактированием. Форматирование текста и пользовательские аннотации сохраняются при изменении конфигурации.

val state = rememberTextFieldState("Formatted text in Compose 1.12")

// Apply bold and color styles to a range of text
state.edit {
    addStyle(
        SpanStyle(fontWeight = FontWeight.Bold, color = Color.Blue),
        start = 0,
        end = 9
    )
}

// Query active styles from TextFieldState
val currentStyles = state.textStyles

Выделение текста

Новый API SelectionState обеспечивает программное управление и наблюдение за выделением текста внутри SelectionContainer . Передача объекта SelectionState через rememberSelectionState() в SelectionContainer позволяет отображать selectedTexts как реактивный список AnnotatedStrings и предоставляет такие методы, как selectAll() , clear() , select(TextRange) и extendSelectionByWord() .

Кроме того, используйте getSelectableTexts() для получения всех выделяемых текстовых элементов в порядке расположения и выделения текста в элементах, входящих в составной контейнер SelectionContainer используя глобальный диапазон.

@Composable
fun ProgrammaticSelectionExample() {
    val selectionState = rememberSelectionState()

    Column {
        Button(
            onClick = { selectionState.selectAll() },
            modifier = Modifier.disableSelectionClearOnTap()
        ) {
            Text("Select All")
        }

        SelectionContainer(state = selectionState) {
            Text("Text content to be selected programmatically.")
        }
    }
}

Интеграция с менеджером учетных данных

Теперь текстовые поля ввода интегрированы с диспетчером учетных данных Android (API 34+) через фреймворк автозаполнения (API ниже 34 обрабатывается androidx.credentials library ). Прикрепив новое свойство семантики credentialRequest к CredentialRequestData , текстовые поля ввода могут запрашивать пароли, сохраненные учетные данные или запросы на вход непосредственно в поток ввода пользователя.

@Composable
fun LoginField(textFieldState: TextFieldState) {
    val credentialData = remember {
        CredentialRequestData(
            // Specify Credential Manager request options
        )
    }

    BasicTextField(
        state = textFieldState,
        modifier = Modifier.semantics {
            credentialRequest = credentialData
        }
    )
}

Другие заметные изменения:

  • Поддержка настроек вариативности шрифта в загружаемых шрифтах .
  • Включена автоматическая прокрутка при перетаскивании выделенного текста за пределы области просмотра в SelectionContainer .
  • Добавлена ​​поддержка автоматических звуков взаимодействия (клики и навигация по фокусу) в компоненты Compose, с новым компонентом SoundEffectOnInteraction , позволяющим отказаться от их использования. Обратите внимание, что в результате этого изменения обработчики кликов теперь должны вызываться из основного потока, что может повлиять на небольшое количество тестовых случаев.
  • KeyboardType теперь включены поля Date , Time , DateTime и SignedDecimal .
  • Теперь BasicSecureTextField по умолчанию использует TextObfuscationMode.System , а RevealLastTyped служит абсолютным переопределением.

Улучшения компоновки

Названия областей в сетке

Создание сложных 2D-макетов теперь стало проще благодаря именованным областям в компоненте @Experimental Grid . Вместо управления числовыми индексами столбцов и строк для элементов, вы можете определить семантические области в GridConfigurationScope и позиционировать компонуемые элементы по имени области.

@OptIn(ExperimentalGridApi::class)
@Composable
fun DashboardLayout() {
    Grid(
        config = {
            area("header", row = 0, column = 0, rowSpan = 1, columnSpan = 2)
            area("sidebar", row = 1, column = 0)
            area("content", row = 1, column = 1)
            gap(16.dp)
        }
    ) {
        HeaderSection(modifier = Modifier.gridItem(areaId = "header"))
        NavigationSidebar(modifier = Modifier.gridItem(areaId = "sidebar"))
        MainContentView(modifier = Modifier.gridItem(areaId = "content"))
    }
}

Для получения более подробной информации см. документацию .

Производительность

Как и в каждом релизе, мы продолжаем инвестировать в повышение производительности Compose, чтобы гарантировать, что фреймворк поможет вам создавать красивые и высокопроизводительные приложения. В этом релизе мы сосредоточились на улучшении производительности при запуске, и теперь наблюдаем время до первого отображения (время, необходимое приложению для вывода первого кадра), сопоставимое с показателями Views в наших бенчмарках .

timetoinitialdisplay@2x _v2.png

Модернизация средств тестирования и инструментов.

Синхронизация тестов

В Compose 1.12 представлены новые API для тестирования, разработанные для сокращения времени выполнения тестов и устранения нестабильности при выборке состояния:

  • hasPendingWork : Пассивно проверяет наличие незавершенной работы в пользовательском интерфейсе без продвижения таймера, что идеально подходит для циклов анимации, создаваемых вручную.
  • runWithoutImplicitWait : Временно отключает неявную синхронизацию при пошаговом выполнении кадров с ручным вводом/выводом (например, в тестах анимации).
@Test
fun testAnimationStateFast() {

composeTestRule.mainClock.autoAdvance = false
    
    while (composeTestRule.hasPendingWork()) {
        composeTestRule.mainClock.advanceTimeByFrame()
        composeTestRule.waitForIdle()
        
        composeTestRule.runOnUiThread {
            composeTestRule.runWithoutImplicitWait {
                // This is most effective when querying multiple nodes in a single frame. 
                // It prevents the redundant synchronization overhead that would 
                // otherwise occur on every individual query.
                val box1 = composeTestRule.onNodeWithTag("Box1").fetchSemanticsNode()
                val box2 = composeTestRule.onNodeWithTag("Box2").fetchSemanticsNode()
                
                assertThat(box1.boundsInRoot.right).isAtMost(box2.boundsInRoot.left)
            }
        }
    }
}

Другие заметные изменения:

  • Теперь API captureToImage позволяет захватывать всплывающее окно или диалоговое окно вместе с его привязкой в ​​одном растровом изображении.
  • Добавлено onRootWithViewInteraction для ограничения области действия семантического поиска Compose определенными представлениями Android. Это упрощает тестирование гибридных пользовательских интерфейсов, таких как RecyclerViews , без необходимости использования уникальных тестовых тегов в рабочем коде.
  • Теперь аннотации @PreviewWrapper можно применять к пользовательским классам @MultiPreview , что позволяет создавать многократно используемые настройки предварительного просмотра (например, пользовательские темы) для нескольких компонентов.

Удачного сочинения!

Compose 1.12 делает разработку приложений проще и выразительнее, чем когда-либо, благодаря сетчатым градиентам, поддержке широкого цветового охвата, загружаемым вариативным шрифтам, интеграции с Credential Manager и более быстрым инструментам тестирования. Как всегда, мы ценим ваши отзывы, поэтому, пожалуйста, поделитесь своим мнением об этих изменениях или о том, что вы хотели бы увидеть в будущем, в нашем трекере проблем . Удачного создания!

Автор:
Продолжить чтение