Jetpack Compose 2025年12月版本新增功能

本文译自「What's new in the Jetpack Compose December '25 release」,原文链接android-developers.googleblog.com/2025/12/wha...,由Nick Butcher发布于2025年12月3日。

现在,Jetpack Compose 2025年12月版本 正式发布。该版本包含 Compose 核心模块 1.10 版和 Material 3 1.4 版(参见完整的 BOM 映射),新增了 多项功能并显著提升了性能。

要使用最新的版本,请将 Compose BOM 版本升级到 2025.12.00:

kotlin 复制代码
implementation(platform("androidx.compose:compose-bom:2025.12.00"))

性能改进

我们知道应用程序的运行时性能对你和你的用户至关重要,因此性能一直是 Compose 团队的首要任务。此版本带来了一系列改进------你只需升级到最新版本即可获得所有这些改进。我们的内部滚动性能基准测试表明,Compose 现在的性能与使用 Views 时的性能相当:

延迟预取中的可暂停组合

延迟预取中的可暂停组合预取功能现已默认启用。这是 Compose 运行时调度机制的一项根本性变革,旨在显著减少高 UI 负载下的卡顿现象。

此前,一旦合成开始,就必须运行至完成。如果合成较为复杂,则可能导致主线程阻塞超过一帧,从而造成 UI 卡顿。而现在,借助可暂停合成功能,运行时可以在时间不足时"暂停"其工作,并在下一帧恢复。当与延迟布局预取结合使用,提前准备帧时,此功能尤为有效。 Compose 1.9 中引入的 LazyLayoutCacheWindow API 可以很好地预取更多内容,并利用可暂停的合成功能来显著提升 UI 性能。

我们还优化了其他方面的性能,例如改进了 Modifier.onPlaced。 Modifier.onVisibilityChanged 和其他修饰符实现。我们将继续投入资源来提升 Compose 的性能。

新功能

Retain

Compose 提供了一系列 API 来跨不同的生命周期保存和管理状态;例如,remember 可以在组合之间持久化状态,而 rememberSavable/rememberSerializable 可以在 Activity 或进程重建之间持久化状态。retain 是一个介于这些 API 之间的新 API,它允许你在配置更改时持久化值而无需序列化,但不会跨进程终止。由于 retain 不会序列化你的状态,因此你可以持久化诸如 lambda 表达式、流程以及位图等难以序列化的大型对象。例如,你可以使用 retain 来管理媒体播放器(例如 ExoPlayer),以确保媒体播放不会因配置更改而中断。

kotlin 复制代码
@Composable
fun MediaPlayer() {
	val applicationContext = LocalContext.current.applicationContext
	val exoPlayer = retain { ExoPlayer.Builder(applicationContext).apply { ... }.build() }
	...
}

我们要感谢 AndroidDev 社区(特别是 Circuit 团队),他们对该功能的设计产生了影响并做出了贡献。

Material 1.4

Material3 库的 1.4.0 版本新增了一些组件和增强功能:

  • TextField 现在提供了一个基于 TextFieldState 的实验性版本,它提供了一种 更强大的 方法来管理文本状态。此外,还新增了变体SecureTextField 和 OutlinedSecureTextField。Material Text 可组合元素现在支持自动调整大小功能(autoSize)。

  • 轮播组件现在提供了一个新的 Horizo​​ntalCenteredHeroCarouselvariant

  • TimePicker 现在支持在选择器模式和输入模式之间切换。

  • 垂直拖拽手柄(VerticalDragHandle)帮助用户更改自适应空格的大小或者位置。

请注意,Material 3 Expressive API 仍在 Material 3 库的 alpha 版本中持续开发。要了解更多信息,请观看最近的演讲

新的动画功能

我们持续扩展动画 API,包括对自定义共享元素动画的更新。

动态共享元素

默认情况下,sharedElement()sharedBounds() 动画会在目标状态中找到匹配的键时尝试为布局更改添加动画效果。但是,你可能希望根据某些条件(例如导航方向或当前 UI 状态)动态禁用​​此动画。

要控制共享元素过渡是否发生,你现在可以自定义传递给 rememberSharedContentState()SharedContentConfigisEnabled 属性决定共享元素是否处于活动状态。

kotlin 复制代码
SharedTransitionLayout {
	val transition = updateTransition(currentState)
	transition.AnimatedContent { targetState ->
		// Create the configuration that depends on state changing.
		fun animationConfig() : SharedTransitionScope.SharedContentConfig {
			return object : SharedTransitionScope.SharedContentConfig {
				override val SharedTransitionScope.SharedContentState.isEnabled: Boolean
						get() =
							// determine whether to perform a shared element transition
                }
            }
}

更多信息,请参阅文档

Modifier.skipToLookaheadPosition()

此版本新增了一个修饰符 Modifier.skipToLookaheadPosition(),用于在执行共享元素动画时保持可组合元素的最终位置。这使得可以执行类似"揭示"类型的过渡动画,例如 Androidify 示例中相机的渐进式揭示效果。更多信息,请参阅此处的视频提示

共享元素过渡中的初始速度

此版本新增了一个共享元素过渡 API:prepareTransitionWithInitialVelocity,允许你将初始速度(例如来自手势)传递给共享元素过渡:

kotlin 复制代码
Modifier.fillMaxSize()
    .draggable2D(
			rememberDraggable2DState{offset+=it},
			onDragStopped = { velocity ->
				// Set up the initial velocity for the upcoming shared element
				// transition.
	          sharedContentStateForDraggableCat?.prepareTransitionWithInitialVelocity(velocity)
				showDetails = false
			},
)

面纱过渡动画

EnterTransitionExitTransition 定义了动画的执行方式。 AnimatedVisibility/ AnimatedContent 可组合元素出现或消失。新增的实验性遮罩选项允许你指定颜色来遮盖或修饰内容;例如,在内容上方淡入/淡出半透明黑色图层:

kotlin 复制代码
AnimatedContent(
    targetState = page,
    modifier = Modifier.fillMaxSize().weight(1f),
    transitionSpec = {
		 if (targetState > initialState) {
            (slideInHorizontally { it } togetherWith
                    slideOutHorizontally { -it / 2 } + veilOut(targetColor = veilColor))
        } else {
            slideInHorizontally { -it / 2 } +
						unveilIn(initialColor = veilColor) togetherWith slideOutHorizontally { it }
        }
    },
) { targetPage ->
    ...
}

即将发生的变更

弃用 Modifier.onFirstVisible

Compose 1.9 引入了 Modifier.onVisibilityChangedModifier.onFirstVisible。在审阅了你的反馈后,我们发现 Modifier.onFirstVisible 的约定无法确定性地执行;具体来说,就是无法确定某个元素何时首次可见。例如,Lazy 布局可能会释放滚动出视口的元素,然后在它们滚动回视口时重新组合它们。在这种情况下,onFirstVisible 回调会再次触发,因为它是一个新组合的元素。当导航回之前访问过的包含 onFirstVisible 的屏幕时,也会出现类似的行为。因此,我们决定在下一个 Compose 版本(1.11)中弃用此修饰符,并建议迁移到 onVisibilityChanged。有关更多信息,请参阅文档

测试中的协程分发

我们计划更改测试中的协程分发,以改善测试的稳定性并捕获更多问题。目前,测试使用的是 UnconfinedTestDispatcher,这与生产环境的行为有所不同;例如,副作用可能会立即运行,而不是被放入队列。在未来的版本中,我们计划引入一个新的 API,默认使用 StandardTestDispatcher,以匹配生产环境的行为。你现在可以在 1.10 版本中尝试新的行为:

kotlin 复制代码
@get:Rule // also createAndroidComposeRule, createEmptyComposeRule
val rule = createComposeRule(effectContext = StandardTestDispatcher())

使用 StandardTestDispatcher 会将任务放入队列,因此你必须使用同步机制,例如 composeTestRule.waitForIdle() 或 composeTestRule.runOnIdle()。如果你的测试使用了 runTest,则必须确保 runTest 和你的 Compose 规则共享同一个 StandardTestDispatcher 实例以进行同步。

kotlin 复制代码
// 1. Create a SINGLE dispatcher instance
valtestDispatcher = StandardTestDispatcher()

// 2. Pass it to your Compose rule
@get:Rule
valcomposeRule = createComposeRule(effectContext = testDispatcher)

@Test
// 3. Pass the *SAME INSTANCE* to runTest
funmyTest() = runTest(testDispatcher) {
	composeRule.setContent{/* ... */}
}

工具

优秀的 API 需要优秀的工具,Android Studio 为 Compose 开发者新增了多项功能:

要查看这些工具的实际应用,请观看此 最新演示

尽情创作

我们持续投入资源开发 Jetpack Compose,为你提供创建美观、丰富的用户界面所需的 API 和工具。我们重视你的反馈,请在我们的问题跟踪器中分享你对这些更改的反馈,或你希望看到的后续功能。

欢迎搜索并关注 公众号「稀有猿诉」 获取更多的优质文章!

保护原创,请勿转载!

相关推荐
Kapaseker1 天前
Compose 进阶—巧用 GraphicsLayer
android·kotlin
黄林晴1 天前
Android17 为什么重写 MessageQueue
android
阿巴斯甜2 天前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker2 天前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95272 天前
Andorid Google 登录接入文档
android
黄林晴2 天前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab2 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿3 天前
Android MediaPlayer 笔记
android
Jony_3 天前
Android 启动优化方案
android
阿巴斯甜3 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android