Berita Produk

Yang baru dalam rilis Jetpack Compose April '26

Waktu baca: 6 menit
Lihat profil Meghan Mehta
Meghan Mehta Developer Advocate, Android

Hari ini, rilis Jetpack Compose April ‘26 sudah stabil. Rilis ini berisi modul Compose inti versi 1.11 (lihat pemetaan BOM lengkap), alat debug elemen bersama, peristiwa trackpad, dan lainnya. Kami juga memiliki beberapa API eksperimental yang ingin kami coba dan beri masukan.

Untuk menggunakan rilis hari ini, upgrade versi BOM Compose Anda ke:

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

Perubahan di Compose 1.11.0

Eksekusi coroutine dalam pengujian

Kami memperkenalkan update besar pada cara Compose menangani pengaturan waktu pengujian. Setelah periode keikutsertaan yang diumumkan di Compose 1.10, API pengujian v2 kini menjadi default, dan API v1 tidak digunakan lagi. Perubahan utamanya adalah peralihan pada dispatcher pengujian default. Meskipun API v1 mengandalkan UnconfinedTestDispatcher, yang langsung mengeksekusi coroutine, API v2 menggunakan StandardTestDispatcher. Artinya, saat coroutine diluncurkan dalam pengujian, coroutine tersebut kini diantrekan dan tidak akan dieksekusi hingga jam virtual dimajukan.

Hal ini lebih meniru kondisi produksi, secara efektif menghilangkan kondisi race, dan membuat suite pengujian Anda jauh lebih andal dan tidak rentan terhadap kegagalan.

Untuk memastikan pengujian Anda selaras dengan perilaku coroutine standar dan untuk menghindari masalah kompatibilitas di masa mendatang, sebaiknya migrasikan suite pengujian Anda. Lihat panduan migrasi kami yang komprehensif untuk mengetahui pemetaan API dan perbaikan umum.

Peningkatan elemen bersama dan alat animasi

Kami juga telah menambahkan beberapa alat proses debug visual yang praktis untuk elemen bersama dan Modifier.animatedBounds. Sekarang Anda dapat melihat dengan jelas apa yang terjadi di balik layar—seperti batas target, lintasan animasi, dan jumlah kecocokan yang ditemukan—sehingga lebih mudah untuk mengetahui alasan transisi mungkin tidak berperilaku seperti yang diharapkan. Untuk menggunakan alat baru, cukup kelilingi SharedTransitionLayout Anda dengan composable LookaheadAnimationVisualDebugging. 

LookaheadAnimationVisualDebugging(
    overlayColor = Color(0x4AE91E63),
    isEnabled = true,
    multipleMatchesColor = Color.Green,
    isShowKeylabelEnabled = false,
    unmatchedElementColor = Color.Red,
) {
    SharedTransitionLayout {
        CompositionLocalProvider(
            LocalSharedTransitionScope provides this,
        ) {
            // your content
        }
    }
}

Peristiwa trackpad

Kami telah meningkatkan dukungan Compose untuk trackpad, seperti trackpad bawaan laptop, trackpad yang dapat dipasang untuk tablet, atau trackpad eksternal/virtual. Peristiwa trackpad dasar kini umumnya akan dianggap sebagai peristiwa PointerType.Mouse, yang menyelaraskan perilaku mouse dan trackpad agar lebih sesuai dengan ekspektasi pengguna. Sebelumnya, peristiwa trackpad ini ditafsirkan sebagai sentuhan jari palsu di layar sentuh PointerType.Touch, yang menyebabkan pengalaman pengguna yang membingungkan. Misalnya, mengklik dan menarik dengan trackpad akan men-scroll, bukan memilih. Dengan mengubah jenis pointer yang dimiliki peristiwa ini dalam rilis terbaru Compose, mengklik dan menarik dengan trackpad tidak akan lagi men-scroll.

Kami juga menambahkan dukungan untuk gestur trackpad yang lebih rumit seperti yang dikenali oleh platform sejak API 34, termasuk geser dua jari dan cubit. Gestur ini otomatis dikenali oleh komponen seperti Modifier.scrollable dan Modifier.transformable agar memiliki perilaku yang lebih baik dengan trackpad.

Perubahan ini meningkatkan perilaku trackpad di seluruh komponen bawaan, dengan penghapusan slop sentuh yang berlebihan, gestur awal tarik lalu lepas yang lebih intuitif, pemilihan klik dua kali dan klik tiga kali di kolom teks, serta menu konteks bergaya desktop di kolom teks.

Untuk menguji perilaku trackpad, ada API pengujian baru dengan performTrackpadInput, yang memungkinkan validasi perilaku aplikasi Anda saat digunakan dengan trackpad. Jika Anda memiliki pendeteksi gestur kustom, validasi perilaku di berbagai jenis input, termasuk layar sentuh, mouse, trackpad, dan stilus, serta pastikan dukungan untuk roda scroll mouse dan gestur trackpad.

beforeAndAfter.webp

Default host komposisi (runtime Compose)

Kami memperkenalkan HostDefaultProvider, LocalHostDefaultProvider, HostDefaultKey, dan ViewTreeHostDefaultKey untuk menyediakan layanan tingkat host secara langsung melalui compose-runtime. Dengan demikian, library tidak perlu bergantung pada compose-ui untuk pencarian, sehingga lebih mendukung Multiplatform Kotlin. Untuk menautkan nilai ini ke hierarki komposisi, penulis library dapat menggunakan compositionLocalWithHostDefaultOf untuk membuat CompositionLocal yang me-resolve default dari host.

Wrapper pratinjau

Pratinjau kustom Android Studio adalah fitur baru yang memungkinkan Anda menentukan dengan tepat cara konten pratinjau Compose ditampilkan.

Dengan mengimplementasikan antarmuka PreviewWrapperProvider dan menerapkan anotasi @PreviewWrapper baru, Anda dapat dengan mudah memasukkan logika kustom, seperti menerapkan Theme tertentu. Anotasi ini dapat diterapkan ke fungsi yang dianotasi dengan @Composable dan @Preview atau @MultiPreview, sehingga menawarkan solusi generik yang mudah digunakan dan berfungsi di seluruh fitur pratinjau serta mengurangi kode berulang secara signifikan.

class ThemeWrapper: PreviewWrapperProvider {
    @Composable
    override fun Wrap(content: @Composable (() -> Unit)) {
        JetsnackTheme {
            content()
        }
    }
}


@PreviewWrapper(ThemeWrapper::class)
@Preview
@Composable
private fun ButtonPreview() {
    // JetsnackTheme in effect
    Button(onClick = {}) {
        Text(text = "Demo")
    }
}

Penghentian penggunaan dan penghapusan

  • Seperti yang diumumkan dalam postingan blog Compose 1.10, kami menghentikan penggunaan Modifier.onFirstVisible(). Namanya sering kali menimbulkan kesalahpahaman, terutama dalam tata letak lambat, yang akan memicu beberapa kali selama men-scroll. Sebaiknya lakukan migrasi ke Modifier.onVisibilityChanged(), yang memungkinkan pelacakan manual status visibilitas yang lebih akurat dan disesuaikan dengan persyaratan kasus penggunaan spesifik Anda.
  • Flag ComposeFoundationFlags.isTextFieldDpadNavigationEnabled dihapus karena navigasi D-pad untuk TextFields kini selalu diaktifkan secara default. Perilaku baru ini memastikan bahwa peristiwa D-pad dari gamepad atau remote TV terlebih dahulu menggerakkan kursor ke arah yang ditentukan. Fokus dapat berpindah ke elemen lain hanya saat kursor mencapai akhir teks.

API mendatang

Dalam rilis Compose 1.12.0 mendatang, compileSdk akan diupgrade ke compileSdk 37, dengan AGP 9 dan semua aplikasi serta library yang bergantung pada Compose mewarisi persyaratan ini. Sebaiknya terus ikuti versi terbaru yang dirilis, karena Compose bertujuan untuk segera mengadopsi compileSdks baru guna memberikan akses ke fitur Android terbaru. Pastikan untuk membaca dokumentasi di sini guna mengetahui informasi selengkapnya tentang versi AGP yang didukung untuk berbagai level API. 

Di Compose 1.11.0, API berikut diperkenalkan sebagai @Experimental, dan kami menantikan masukan Anda saat Anda menjelajahinya di aplikasi Anda. Perhatikan bahwa @Experimental APIs disediakan untuk evaluasi dan masukan awal, serta dapat mengalami perubahan signifikan atau dihapus dalam rilis mendatang.

Gaya (Eksperimental)

Kami memperkenalkan API dasar eksperimental baru untuk penataan gaya. Style API adalah paradigma baru untuk menyesuaikan elemen visual komponen, yang biasanya dilakukan dengan pengubah. Fitur ini dirancang untuk memungkinkan penyesuaian yang lebih mendalam dan mudah dengan mengekspos set standar properti yang dapat diberi gaya dengan gaya visual berbasis status dan transisi animasi yang sederhana. Dengan API baru ini, kami telah melihat manfaat performa yang menjanjikan. Kami berencana untuk mengadopsi Gaya di komponen Material setelah Style API stabil.

Contoh dasar penggantian latar belakang gaya status ditekan:

@Composable
fun LoginButton(modifier: Modifier = Modifier) {
    Button(
        onClick = {
            // Login logic
        },
        modifier = modifier,
        style = {
            background(
                Brush.linearGradient(
                    listOf(lightPurple, lightBlue)
                )
            )
            width(75.dp)
            height(50.dp)
            textAlign(TextAlign.Center)
            externalPadding(16.dp)

            pressed {
                background(
                    Brush.linearGradient(
                        listOf(Color.Magenta, Color.Red)
                    )
                )
            }
        }
    ){
        Text(
            text = "Login",
        )
    }
}
styles.webp

Lihat dokumentasi dan laporkan bug di sini.

MediaQuery (Eksperimental)

API mediaQuery baru menyediakan cara deklaratif dan berperforma tinggi untuk menyesuaikan UI dengan lingkungannya. Fungsi ini mengabstraksi pengambilan informasi yang kompleks menjadi kondisi sederhana dalam UiMediaScope, sehingga rekomposisi hanya terjadi saat diperlukan.

Dengan dukungan untuk berbagai sinyal lingkungan—mulai dari kemampuan perangkat seperti jenis keyboard dan presisi pointer, hingga status kontekstual seperti ukuran dan postur jendela—Anda dapat membangun pengalaman yang sangat responsif. Performa dioptimalkan dengan derivedMediaQuery untuk menangani update frekuensi tinggi, sementara kemampuan untuk mengganti cakupan membuat pengujian dan pratinjau berjalan lancar di berbagai konfigurasi hardware. Sebelumnya, untuk mendapatkan akses ke properti perangkat tertentu — seperti apakah perangkat berada dalam mode di atas meja — Anda harus menulis banyak boilerplate untuk melakukannya: 

@Composable
fun isTabletopPosture(
    context: Context = LocalContext.current
): Boolean {
    val windowLayoutInfo by
        WindowInfoTracker
            .getOrCreate(context)
            .windowLayoutInfo(context)
            .collectAsStateWithLifecycle(null)

    return windowLayoutInfo.displayFeatures.any { displayFeature ->
        displayFeature is FoldingFeature &&
            displayFeature.state == FoldingFeature.State.HALF_OPENED &&
            displayFeature.orientation == FoldingFeature.Orientation.HORIZONTAL
    }
}

@Composable
fun VideoPlayer() {
    if(isTabletopPosture()) {
        TabletopLayout()
    } else {
        FlatLayout()
    }
}

Sekarang, dengan UIMediaQuery, Anda dapat menambahkan sintaksis mediaQuery untuk mengkueri properti perangkat, seperti apakah perangkat dalam mode di atas meja:

@OptIn(ExperimentalMediaQueryApi::class)
@Composable
fun VideoPlayer() {
    if (mediaQuery { windowPosture == UiMediaScope.Posture.Tabletop }) {
        TabletopLayout()
    } else {
        FlatLayout()
    }
}

Lihat dokumentasi dan laporkan bug di sini.

Petak (Eksperimental)

Grid adalah API baru yang canggih untuk membuat tata letak dua dimensi yang kompleks di Jetpack Compose. Meskipun Row dan Column cocok untuk desain linear, Grid memberi Anda kontrol struktural yang diperlukan untuk arsitektur tingkat layar dan komponen yang rumit tanpa overhead daftar yang dapat di-scroll. Grid memungkinkan Anda menentukan tata letak menggunakan jalur, celah, dan sel, yang menawarkan opsi ukuran yang sudah dikenal seperti Dp, persentase, ukuran konten intrinsik, dan unit "Fr" yang fleksibel. 

@OptIn(ExperimentalGridApi::class)
@Composable
fun GridExample() {
    Grid(
        config = {
            repeat(4) { column(0.25f) }
            repeat(2) { row(0.5f) }
            gap(16.dp)
        }
    ) {
        Card1(modifier = Modifier.gridItem(rowSpan = 2)
        Card2(modifier = Modifier.gridItem(colmnSpan = 3)
        Card3(modifier = Modifier.gridItem(columnSpan = 2)
        Card4()
    }
}

Anda dapat menempatkan item secara otomatis atau secara eksplisit merentangkannya di beberapa baris dan kolom untuk presisi. Yang terbaik dari semuanya, tata letak ini sangat adaptif—Anda dapat mengonfigurasi ulang jalur dan rentang petak secara dinamis untuk merespons status perangkat seperti mode di atas meja atau perubahan orientasi, sehingga memastikan UI Anda terlihat bagus di berbagai faktor bentuk.

Grid.gif

Lihat dokumentasi dan laporkan bug di sini. 

FlexBox (Eksperimental)

FlexBox adalah penampung tata letak yang dirancang untuk UI adaptif berperforma tinggi. Flexbox mengelola ukuran item dan distribusi ruang berdasarkan dimensi penampung yang tersedia.  Model ini menangani tugas kompleks seperti penggabungan (wrap) dan perataan multi-sumbu item (justifyContent, alignItems, alignContent). Model ini memungkinkan item bertambah (grow) atau menyusut (shrink) untuk mengisi penampung. 

@OptIn(ExperimentalFlexBoxApi::class)
fun FlexBoxWrapping(){
    FlexBox(
        config = {
            wrap(FlexWrap.Wrap)
            gap(8.dp)
        }
    ) {
        RedRoundedBox()
        BlueRoundedBox()
        GreenRoundedBox(modifier = Modifier.width(350.dp).flex { grow(1.0f) })
        OrangeRoundedBox(modifier = Modifier.width(200.dp).flex { grow(0.7f) })
        PinkRoundedBox(modifier = Modifier.width(200.dp).flex { grow(0.3f) })
    }
}
AnimationGif.gif

Lihat dokumentasi dan laporkan bug di sini.

Implementasi SlotTable baru (Eksperimental)

Kami telah memperkenalkan implementasi baru SlotTable, yang dinonaktifkan secara default dalam rilis ini. SlotTable adalah struktur data internal yang digunakan runtime Compose untuk melacak status hierarki komposisi Anda, melacak pembatalan/rekomposisi, menyimpan nilai yang diingat, dan melacak semua metadata komposisi saat runtime. Implementasi baru ini dirancang untuk meningkatkan performa, terutama terkait pengeditan acak.

Untuk mencoba SlotTable baru, aktifkan ComposeRuntimeFlags.isLinkBufferComposerEnabled. 

Mulai coding sekarang juga.

Dengan begitu banyak API baru yang menarik di Jetpack Compose, dan masih banyak lagi yang akan hadir, sekarang adalah saat yang tepat untuk bermigrasi ke Jetpack Compose.  Seperti biasa, kami menghargai masukan dan permintaan fitur Anda (terutama terkait fitur @Experimental yang masih dalam pengembangan) — harap ajukan di sini. Selamat belajar menulis kode!

Ditulis oleh:
Lanjutkan membaca