Berita Produk

Yang baru di rilis Jetpack Compose Agustus '26

Waktu baca: 5 menit
Lihat profil Nick Butcher
Nick Butcher Product Manager

Hari ini, rilis Jetpack Compose Agustus '26 sudah stabil. Rilis ini menghadirkan versi 1.12 di seluruh modul Compose inti (lihat pemetaan BOM lengkap), memperkenalkan API visual yang kaya seperti Gradien Mesh dan dukungan Wide Color Gamut (WCG), fitur tata letak struktural seperti area bernama di Grid, integrasi yang lancar dengan Pengelola Kredensial Android, serta peningkatan pengujian dan performa yang signifikan.

Untuk mengupdate project Anda ke rilis hari ini, upgrade versi BOM Compose Anda ke 2026.08.00:

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

Perubahan yang Dapat Menyebabkan Gangguan

  • AGP & Compile SDK: Compose 1.12 mengupdate compileSdk ke API 37, yang memerlukan AGP 9.1.2 minimum. Sebagai pengingat, Compose akan selalu menargetkan compileSdk terbaru. Pelajari perubahan ini lebih lanjut di sini.
  • Modifier.onFirstVisible() tidak digunakan lagi: Lakukan migrasi ke Modifier.onVisibilityChanged(), yang memberikan tracking nilai minimum visibilitas yang lebih presisi.

Grafis

Gradien Mesh

Compose 1.12 memperkenalkan MeshGradientPainter untuk membantu Anda membuat gradien warna organik multi-titik.

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

Untuk mengetahui informasi dan contoh selengkapnya, lihat dokumentasi .

Dukungan HDR & Wide Color Gamut

Layar modern menawarkan fidelitas warna yang lebih baik dan rentang dinamis yang lebih tinggi. Di Compose 1.12, dukungan pipeline penuh untuk Wide Color Gamut (P3) dan rendering HDR telah diaktifkan di seluruh grafis, paint, dan shader Compose. Warna yang ditentukan dalam ruang warna non-sRGB (seperti Display P3) dipertahankan hingga rendering platform tanpa penjepitan warna. Warna akan kembali ke sRGB dengan aman jika menggunakan ruang warna yang tidak didukung (misalnya CieXyz, CieLab, atau Oklab), mengandalkan ruang warna pada versi Android yang tidak didukung (misalnya Bt2020Hlg di Android 13 dan yang lebih lama), atau jika aplikasi berjalan di Android 9 (API 28) dan yang lebih lama.

Perubahan penting lainnya:

  • LayerOutsets ditambahkan ke GraphicsLayerModifier.graphicsLayer, yang dapat Anda gunakan untuk memperluas batas visual lapisan di luar ukuran yang diukur. Terapkan LayerOutsets untuk menghindari perilaku clipToBounds implisit saat lapisan dipromosikan ke buffer di luar layar.

Gaya

Di Google I/O, kami membagikan visi awal kami untuk Styles API Compose—cara terpadu dan berperforma tinggi untuk menata gaya komponen. Sejak saat itu, kami terus membangun arsitektur yang mendasarinya untuk menjamin keamanan jenis yang ketat dan kebenaran yang dapat diprediksi, serta untuk mendukung pembangunan sistem desain kustom. 

Untuk memastikan kami mendapatkan lapisan dasar ini dengan benar, API akan tetap bersifat eksperimental, dan Anda dapat mengharapkan perubahan yang merusak. 

Pengoptimalan Runtime

Keyed SideEffect Overload

SideEffect kini mendukung argumen kunci, yang memungkinkan Anda memicu efek samping sekali pakai setiap kali kunci tertentu berubah. Hal ini dapat menghasilkan performa yang lebih baik dibandingkan dengan menggunakan LaunchedEffect atau DisposableEffect saat Anda tidak memerlukan coroutine atau blok pelepasan. SideEffect hingga 90% lebih cepat daripada LaunchedEffect dan sekitar 20% lebih cepat daripada DisposableEffect. Perhatikan bahwa SideEffect menjalankan efeknya sebelum DisposableEffect dan LaunchedEffect, jadi berhati-hatilah jika memigrasikan efek yang ada ke API ini, terutama untuk LaunchedEffects yang mengandalkan pengiriman untuk dimulai setelah frame saat ini selesai. 

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

Animasi

Transisi Dua Tahap Interaktif

  • Composable baruDeferredAnimatedContent dan DeferredAnimatedVisibility memungkinkan pembuatan transisi dua tahap yang menarik, misalnya untuk pelacakan gestur kembali prediktif.
  • Kontrol animasi manual: Selama fase tertunda transisi, properti animasi (seperti skala atau offset) kini dapat dimanipulasi secara manual dalam real-time (misalnya, melacak gestur geser).
  • Penyerahan yang lancar: Setelah fase yang ditangguhkan berakhir, mesin transisi mengambil alih dan melakukan penyerahan yang lancar, termasuk transfer kecepatan, ke transisi otomatis.
  • Dukungan elemen bersama: Flag permitTransformDuringDeferredTransition baru di SharedContentConfig mengontrol apakah elemen bersama bertransformasi secara visual bersama dengan penampung induknya selama fase transisi yang ditangguhkan.
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)
}

Di bawah ini adalah dua demo kasus penggunaan saat animasi yang digerakkan oleh gestur diserahkan ke animasi yang dipicu:

colorCards.gif

Integrasi Teks, Input & Platform

Pemformatan Teks yang Dapat Diedit

API baru menawarkan format rich text untuk teks yang dapat diedit di BasicTextField. Anda kini dapat menerapkan dan memanipulasi pemformatan karakter dan paragraf sebaris secara terprogram menggunakan SpanStyle dan ParagraphStyle melalui metode addStyle() baru dalam cakupan TextFieldBuffer (seperti dalam textFieldState.edit { ... } atau InputTransformation). Selain itu, TextFieldBuffer menyediakan API getSpanStyles() dan getParagraphStyles() yang menampilkan objek TrackedRange, sehingga Anda dapat membaca, memperbarui, atau menghapus gaya yang diterapkan. Untuk melengkapi pembuatan format, TextFieldState kini mengekspos properti textStyles hanya baca untuk pembuatan kueri gaya aktif di seluruh rentang, sementara TextFieldBuffer menyediakan originalTextStyles untuk memeriksa status pemformatan sebelum pengeditan. Pemformatan teks dan anotasi kustom dipertahankan di seluruh perubahan konfigurasi.

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

Pemilihan Teks

API SelectionState baru memberikan kontrol dan kemampuan pengamatan terprogram atas pemilihan teks dalam SelectionContainer. Mengangkat objek SelectionState melalui rememberSelectionState() dan meneruskannya ke SelectionContainer akan mengekspos selectedTexts sebagai daftar reaktif AnnotatedStrings dan menyediakan metode seperti selectAll()clear()select(TextRange), dan extendSelectionByWord().

Selain itu, gunakan getSelectableTexts() untuk mengambil semua item teks yang dapat dipilih dalam urutan tata letak dan memilih teks di seluruh composable dalam SelectionContainer menggunakan rentang global. 

@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.")
        }
    }
}

Integrasi Pengelola Kredensial

Kolom teks Compose kini terintegrasi secara native dengan Credential Manager Android (API 34+) melalui framework Isi Otomatis (di bawah API 34 ditangani oleh androidx.credentials library). Dengan melampirkan properti semantik credentialRequest baru dengan CredentialRequestData, input teks dapat memunculkan kunci sandi, kredensial tersimpan, atau permintaan login langsung dalam alur input pengguna.

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

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

Perubahan penting lainnya:

  • Dukungan untuk setelan variasi font di font yang dapat didownload.
  • Mengaktifkan scroll otomatis saat menarik pilihan teks di luar area tampilan di SelectionContainer.
  • Menambahkan dukungan untuk suara interaksi otomatis (klik dan navigasi fokus) ke komponen Compose, dengan composable SoundEffectOnInteraction baru untuk memungkinkan penonaktifan. Perhatikan bahwa sebagai konsekuensi dari perubahan ini, pemroses klik semantik kini harus dipanggil dari thread utama, yang dapat memengaruhi sejumlah kecil kasus pengujian.
  • KeyboardType kini menyertakan DateTimeDateTime, dan SignedDecimal.
  • BasicSecureTextField kini menggunakan TextObfuscationMode.System secara default, sementara RevealLastTyped berfungsi sebagai penggantian mutlak.

Penyempurnaan Tata Letak

Area Bernama dalam Tata Letak Petak

Membangun tata letak 2D yang kompleks kini lebih mudah dengan area bernama dalam komponen @Experimental Grid. Daripada mengelola indeks kolom dan baris numerik di seluruh item, Anda dapat menentukan region semantik di GridConfigurationScope dan memosisikan composable berdasarkan nama area.

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

Untuk mengetahui informasi selengkapnya, lihat dokumentasi.

Performa

Seperti setiap rilis, kami terus berinvestasi dalam performa Compose untuk memastikan framework ini membantu Anda membangun aplikasi yang indah dan berperforma tinggi. Dalam rilis ini, kami berfokus pada peningkatan kinerja startup dan sekarang melihat Waktu ke Tampilan Awal (waktu yang dibutuhkan aplikasi untuk menghasilkan frame pertamanya) yang sebanding dengan Views dalam benchmark kami.

timetoinitialdisplay@2x _v2.png

Peningkatan Kualitas Pengujian & Alat

Sinkronisasi Uji

Compose 1.12 memperkenalkan API pengujian baru yang dirancang untuk mengurangi waktu eksekusi pengujian dan menghilangkan ketidakpastian selama pengambilan sampel status:

  • hasPendingWork: Secara pasif memeriksa apakah UI memiliki pekerjaan yang tertunda tanpa memajukan clock, yang ideal untuk loop animasi manual.
  • runWithoutImplicitWait: Menonaktifkan sinkronisasi implisit untuk sementara saat menelusuri frame jam manual (misalnya, pengujian animasi).
@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)
            }
        }
    }
}

Perubahan penting lainnya:

  • API captureToImage kini memungkinkan Anda mengambil pop-up atau dialog bersama dengan anchor-nya dalam satu bitmap.
  • DitambahkanonRootWithViewInteraction Untuk membatasi pencarian semantik ke Tampilan Android tertentu. Hal ini menyederhanakan pengujian UI hibrida, seperti RecyclerViews, tanpa memerlukan tag pengujian unik dalam kode produksi.
  • @PreviewWrapperAnotasi kini dapat diterapkan pada kustom.@MultiPreview kelas, memungkinkan pengaturan pratinjau yang dapat digunakan kembali (seperti tema khusus) di berbagai komponen.

Selamat Menyusun!

Compose 1.12 membuat pengembangan aplikasi lebih mudah dan lebih ekspresif dari sebelumnya, dengan gradien mesh, dukungan gamut warna yang luas, font variabel yang dapat diunduh, integrasi Pengelola Kredensial, dan alat pengujian yang lebih cepat. Seperti biasa, kami menghargai masukan Anda. Jadi, sampaikan masukan Anda tentang perubahan ini atau apa yang ingin Anda lihat selanjutnya di pelacak masalah kami. Selamat menyusun!

Ditulis oleh:
Lanjutkan membaca