产品新闻

Jetpack Compose 2026 年 8 月版的最新动态

阅读用时:5 分钟
查看 Nick Butcher 的个人资料
Nick Butcher 产品经理

今天,Jetpack Compose 2026 年 8 月版已是稳定版!此版本在核心 Compose 模块中引入了 1.12 版(请参阅完整的 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 中,Compose 图形、Paint 和着色器已全面支持 Wide Color Gamut (P3) 和 HDR 渲染。在非 sRGB 颜色空间(例如 Display P3)中定义的颜色会保留到平台渲染,而不会进行颜色钳制。如果颜色使用不受支持的颜色空间(例如 CieXyz、CieLab 或 Oklab),依赖于不受支持的 Android 版本上的颜色空间(例如 Android 13 及更低版本上的 Bt2020Hlg),或者应用在 Android 9(API 28)及更低版本上运行,则颜色将安全地回退到 sRGB。

其他值得注意的变更:

  • LayerOutsets 已添加到 GraphicsLayer 和 Modifier.graphicsLayer,您可以使用它将图层的视觉边界扩展到超出其测量大小。应用 LayerOutsets 可避免在图层升级为屏外缓冲区时出现隐式 clipToBounds 行为。

样式

在 Google I/O 大会上,我们分享了 Compose Styles API 的早期愿景,即以统一、高效的方式为组件设置样式。自那时起,我们一直在构建底层架构,以保证严格的类型安全性和可预测的正确性,并支持构建自定义设计系统。

为确保我们正确构建这一基础层,该 API 将保持实验性状态,并且您可能会遇到重大变更。

运行时优化

键控副作用重载

SideEffect 现在支持键实参,让您可以在特定键发生变化时触发一次性副作用。与在不需要协程或处置块时使用 LaunchedEffect 或 DisposableEffect 相比,这可以带来更好的性能。SideEffect 比 LaunchedEffect 快 90%,比 DisposableEffect 快 20% 左右。请注意,SideEffect 在 DisposableEffect 和 LaunchedEffect 之前运行其效果,因此,如果将现有效果迁移到此 API,请务必谨慎,尤其是对于依赖于在当前帧完成后分派以启动的 LaunchedEffects。

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

动画

互动式两阶段过渡

  • 新的可组合项:DeferredAnimatedContent 和 DeferredAnimatedVisibility 可用于创建令人愉悦的两阶段过渡效果,例如用于预测性返回手势跟踪。
  • 手动动画控制:在过渡的延迟阶段,现在可以实时手动操作动画属性(例如缩放或偏移),例如跟踪滑动操作。
  • 无缝切换:延迟阶段结束后,过渡引擎会接管并执行无缝切换(包括速度转移),以实现自动过渡。
  • 共享元素支持:SharedContentConfig 中的新标志 permitTransformDuringDeferredTransition 用于控制共享元素是否在延迟过渡阶段随其父容器一起进行视觉转换。
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 通过 TextFieldBuffer 范围(例如 textFieldState.edit { ... } 或 InputTransformation 内)中的新 addStyle() 方法,以编程方式应用和操纵内嵌字符和段落格式。此外,TextFieldBuffer 还提供 getSpanStyles() 和 getParagraphStyles() API,这些 API 会返回 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

文本选择

新的 SelectionState API 可提供对 SelectionContainer 内文本选择的程序化控制和可观测性。通过 rememberSelectionState() 提升 SelectionState 对象并将其传递到 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.")
        }
    }
}

Credential Manager 集成

Compose 文本字段现在通过自动填充框架(API 34 以下版本由 androidx.credentials library 处理)与 Android 的 Credential Manager(API 34 及更高版本)原生集成。通过附加新的 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 用作绝对替换项。

布局增强功能

网格布局中的命名区域

现在,借助 @Experimental 网格组件中的命名区域,您可以更轻松地构建复杂的 2D 布局。您无需跨多个项管理数字列和行索引,而是可以在 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 的性能,以确保该框架可帮助您构建美观且高性能的应用。在此版本中,我们专注于提升启动性能,现在初步显示所用时间(应用生成第一帧所用的时间)已达到与 benchmark 中 View 相当的水平。

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)
            }
        }
    }
}

其他值得注意的变更:

  • captureToImage API 现在允许您在单个位图中同时捕获弹出式窗口或对话框及其锚点。
  • 添加了 onRootWithViewInteraction,以将 Compose 语义搜索限定为特定的 Android 视图。这样一来,您无需在生产代码中使用唯一的测试标记,即可简化混合界面的测试,例如 RecyclerViews。
  • @PreviewWrapper 注解现在可以应用于自定义 @MultiPreview 类,从而实现跨多个组件的可重复使用的预览设置(例如自定义主题)。

祝您编程愉快!

Compose 1.12 提供了网格渐变、广色域支持、可下载的可变字体、凭据管理器集成和更快的测试工具,让应用开发比以往更轻松、更富有表现力。我们一如既往地重视您的意见,因此请在我们的问题跟踪器中分享您对这些变更的反馈,或您希望我们接下来做些什么。祝编程顺利!

继续阅读