產品最新消息

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 和編譯 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 Graphics、Paint 和 Shader 已全面支援廣色域 (P3)HDR 顯示。在非 sRGB 色域 (例如 Display P3) 中定義的顏色會保留至平台算繪,不會受到顏色箝制。如果顏色使用不支援的色域 (例如 CieXyz、CieLab 或 Oklab)、依賴不支援的 Android 版本色域 (例如 Android 13 以下版本的 Bt2020Hlg),或應用程式在 Android 9 (API 28) 以下版本上執行,系統會安全地將顏色還原為 sRGB。

其他重要變更:

  • LayerOutsets 已加入 GraphicsLayerModifier.graphicsLayer 中,您可以使用它們來增加圖層的視覺邊界,使其超出其測量大小。當圖層升級為螢幕外緩衝區時,請套用 LayerOutsets,避免隱含的 clipToBounds 行為。

樣式

在 Google I/O 大會上,我們分享了我們對 Compose Styles API 的早期願景——一種統一、高效能的元件樣式設定方式。自此,我們持續建構基礎架構,確保嚴格的類型安全性和可預測的正確性,並支援建構自訂設計系統。

為了確保基礎層正確無誤,API 將保持實驗狀態,您可能會遇到一些重大變更。

執行階段最佳化

鍵控 SideEffect 多載

SideEffect 現在支援鍵引數,可讓您在特定鍵變更時觸發一次性副作用。與使用 LaunchedEffectDisposableEffect 相比,如果您不需要協同程式或處置區塊,這項做法可帶來更優異的效能。SideEffect 的速度比 LaunchedEffect 快 90%,比 DisposableEffect 快 20%。請注意,SideEffect 會在 DisposableEffectLaunchedEffect 之前執行效果,因此將現有效果遷移至這個 API 時請務必小心,尤其是依賴在目前影格完成後才開始調度的 LaunchedEffects

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

動畫

互動式兩階段過渡

  • 新可組合函式DeferredAnimatedContentDeferredAnimatedVisibility 可用於建立令人愉悅的兩階段轉場效果,例如預測返回手勢追蹤。
  • 手動控制動畫:在轉場效果的延遲階段,現在可以手動即時操控動畫屬性 (例如縮放或位移),例如追蹤滑動手勢。
  • 無縫交接: 一旦延遲階段結束,過渡引擎就會接管並執行無縫交接,包括速度轉移,到自動過渡。
  • 共用元素支援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 中編輯文字,並設定 RTF 格式。您現在可以透過程式,使用 SpanStyleParagraphStyle,在 TextFieldBuffer 範圍內 (例如 textFieldState.edit { ... }InputTransformation 內) 的新 addStyle() 方法中,套用及操控內嵌字元和段落格式。此外,TextFieldBuffer 提供 getSpanStyles()getParagraphStyles() 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 文字欄位現在會透過自動填入架構,與 Android 的 Credential Manager (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 現在包含 DateTimeDateTimeSignedDecimal
  • BasicSecureTextField 現在預設會使用 TextObfuscationMode.System,而 RevealLastTyped 則做為絕對覆寫。

版面配置強化功能

格狀版面配置中的具名區域

現在,您可以使用 @Experimental Grid 元件中的具名區域,更輕鬆地建構複雜的 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 的效能,確保這個架構能協助您建構美觀且高效能的應用程式。我們在這次發布中著重於提升啟動效能,現在的初始顯示時間 (應用程式產生第一個影格所需的時間) 與基準中的 Views 相當。

timetoinitialdisplay@2x _v2.png

測試與工具升級

測試同步

Compose 1.12 推出新的測試 API,可縮短測試執行時間,並在狀態取樣期間消除不穩定性:

  • hasPendingWork:被動檢查 UI 是否有待處理的工作,但不會推進時鐘,非常適合手動動畫迴圈。
  • 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 檢視區塊。這樣一來,您就能簡化混合式 UI 的測試作業 (例如 RecyclerViews),不必在正式版程式碼中加入專屬測試標記。
  • 現在可將 @PreviewWrapper 註解套用至自訂 @MultiPreview 類別,在多個元件中啟用可重複使用的預覽設定 (例如自訂主題)。

祝您編寫愉快!

Compose 1.12 推出網格漸層、廣色域支援、可下載的變數字型、憑證管理工具整合功能,以及更快速的測試工具,讓應用程式開發作業比以往更輕鬆且更具表現力。我們一向重視您的想法,歡迎透過問題追蹤器分享您對這些變更的意見,或提出您希望我們接下來推出的功能。祝編寫愉快!

繼續閱讀