Mode jendela desktop memungkinkan pengguna menjalankan beberapa aplikasi secara bersamaan di jendela aplikasi yang dapat diubah ukurannya untuk pengalaman serbaguna seperti desktop.
Pada gambar 1, Anda dapat melihat pengaturan layar dengan mode jendela desktop yang diaktifkan. Hal-hal yang perlu diperhatikan:
- Pengguna dapat menjalankan beberapa aplikasi secara berdampingan secara bersamaan.
- Taskbar berada di posisi tetap di bagian bawah layar yang menampilkan aplikasi yang sedang berjalan. Pengguna dapat menyematkan aplikasi untuk akses cepat.
- Panel header baru yang dapat disesuaikan menghiasi bagian atas setiap jendela dengan kontrol seperti minimalkan dan maksimalkan.
Secara default, aplikasi akan terbuka dalam layar penuh di tablet Android. Untuk meluncurkan aplikasi dalam mode jendela desktop, tekan lama tuas jendela di bagian atas layar dan tarik tuas dalam UI, seperti yang terlihat pada gambar 2.
Saat aplikasi dibuka dalam mode jendela desktop, aplikasi lain juga akan dibuka di jendela desktop.
Pengguna juga dapat memanggil mode jendela desktop dari menu yang muncul di bawah handle jendela saat Anda mengetuk atau mengklik handle atau menggunakan pintasan keyboard Tombol Meta (Windows, Command, atau Penelusuran) + Ctrl + Panah Bawah.
Pengguna keluar dari mode jendela desktop dengan menutup semua jendela aktif atau dengan mengambil tuas jendela di bagian atas jendela desktop dan menarik aplikasi ke bagian atas layar. Pintasan keyboard Meta + H juga akan keluar dari mode jendela desktop dan menjalankan aplikasi dalam layar penuh lagi.
Untuk kembali ke mode jendela desktop, ketuk atau klik ubin ruang desktop di layar Terbaru.
Mengoptimalkan tata letak aplikasi untuk lingkungan seperti desktop
Mendesain untuk pengalaman desktop dapat berbeda secara signifikan dari desain seluler karena ruang layar yang lebih besar, presisi input mouse dan keyboard, serta ekspektasi produktivitas yang tinggi.
Jetpack WindowManager menyediakan API yang tegas untuk membantu developer memutuskan kapan harus menampilkan UI desktop, yang biasanya memiliki kepadatan informasi yang lebih tinggi, pola navigasi yang berbeda, dan interaksi mouse yang dioptimalkan.
lifecycleScope.launch(Dispatchers.Main) { lifecycle.repeatOnLifecycle(Lifecycle.State.STARTED) { windowInfoTracker.windowEngagementInfo(this@DesktopWindowingActivity) .collect { windowEngagementInfo -> if(windowEngagementInfo.hasEngagementMode(WindowEngagementInfo.EngagementMode.PRECISE_POINTER)){ showDesktopOptimizedUI() }else { showTouchOptimizedUI() } } } }
Untuk mempelajari lebih lanjut, lihat Mendesain untuk desktop.
Mode kompatibilitas dan kemampuan pengubahan ukuran
Dalam mode jendela desktop, aplikasi dengan orientasi terkunci dapat diubah ukurannya secara bebas. Artinya, meskipun aktivitas dikunci ke orientasi potret, pengguna masih dapat mengubah ukuran aplikasi ke jendela orientasi lanskap.
Aplikasi yang dideklarasikan sebagai tidak dapat diubah ukurannya (yaitu, resizeableActivity = false) akan
diskalakan UI-nya dengan tetap mempertahankan rasio aspek yang sama.
Aplikasi kamera yang mengunci orientasi atau dideklarasikan sebagai tidak dapat diubah ukurannya memiliki perlakuan khusus untuk jendela bidik kameranya: jendela dapat diubah ukurannya sepenuhnya, tetapi jendela bidik mempertahankan rasio aspek yang sama. Dengan mengasumsikan aplikasi selalu berjalan dalam mode potret atau lanskap, aplikasi melakukan hardcode atau membuat asumsi yang menyebabkan kesalahan penghitungan orientasi atau rasio aspek pratinjau atau gambar yang diambil, sehingga menghasilkan gambar yang melebar, miring, atau terbalik.
Hingga aplikasi siap menerapkan jendela bidik kamera yang sepenuhnya responsif, perlakuan khusus memberikan pengalaman pengguna yang lebih mendasar yang mengurangi efek yang mungkin disebabkan oleh asumsi yang salah.
Untuk mempelajari lebih lanjut mode kompatibilitas untuk aplikasi kamera, lihat Mode kompatibilitas perangkat.
Inset header yang dapat disesuaikan
Semua aplikasi yang berjalan dalam mode jendela desktop memiliki panel header, bahkan dalam mode imersif. Anda dapat menyesuaikan panel ini untuk mencegah konten aplikasi Anda terhalang dan menggambar elemen UI kustom langsung ke ruang header.
Penerapan
Untuk menggambar konten kustom di panel header, langkah pertama adalah membuat latar belakang panel header menjadi transparan. Anda dapat melakukannya menggunakan flag APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND dengan WindowInsetsController.
window.insetsController?.setSystemBarsAppearance( WindowInsetsController.APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND, WindowInsetsController.APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND )
Setelah panel header transparan, Anda dapat menata gaya area header agar sesuai dengan
desain aplikasi Anda. Gunakan WindowInsets.isCaptionBarVisible untuk mendeteksi apakah panel
ada dan menerapkan tinggi atau padding yang sesuai ke tata letak Anda.
@OptIn(ExperimentalLayoutApi::class) @Composable fun CaptionBar() { if (WindowInsets.isCaptionBarVisible) { Row( modifier = Modifier .windowInsetsTopHeight(WindowInsets.captionBar) .fillMaxWidth() .background(if (isSystemInDarkTheme()) Color.White else Color.Black), horizontalArrangement = Arrangement.Center, verticalAlignment = Alignment.CenterVertically ) { Text( text = "Caption Bar Title", style = MaterialTheme.typography.titleMedium, modifier = Modifier.padding(4.dp) ) } } }
setSystemBarsAppearance(appearance,mask): Mengonfigurasi gaya visual kolom sistem. Parameter pertama menentukan flag tampilan target, sedangkan parameter kedua bertindak sebagai mask untuk mengontrol flag tertentu yang diubah.windowInsetsTopHeight(): Otomatis menetapkan tinggi Composable agar sesuai dengan panel header sistem, sehingga membantu latar belakang kustom Anda mengisi area teks tanpa melakukan hardcode nilai piksel.WindowInsets.captionBar: Memberikan dimensi untuk kontrol mode jendela desktop (Tutup, Maksimalkan, dll.), sehingga UI Anda dapat diskalakan atau disembunyikan secara otomatis saat masuk atau keluar dari mode jendela desktop.
Untuk mengetahui informasi selengkapnya, lihat Tentang inset jendela. Selain judul, Anda dapat menampilkan elemen UI lainnya di panel judul, seperti tab—seperti di Google Chrome—kotak penelusuran, atau avatar profil.
Antarmuka pengguna
Untuk menghindari tumpang-tindih UI Anda dengan tombol sistem, Android 15 menyediakan
metode WindowInsets#getBoundingRects(). Metode ini menampilkan daftar objek
Rect yang mewakili area yang ditempati oleh elemen sistem. Setiap ruang
yang tersisa di panel judul adalah zona aman tempat Anda dapat menempatkan konten
kustom dengan aman.
Aktifkan/nonaktifkan tampilan elemen teks sistem untuk tema terang dan gelap menggunakan
APPEARANCE_LIGHT_CAPTION_BARS. Akses inset menggunakan
WindowInsets.Companion.captionBar() di Compose, atau
WindowInsets.Type.captionBar() di View.
Untuk mengetahui informasi selengkapnya, lihat Tentang inset jendela.
Dukungan multitasking dan multi-instance
Multitasking adalah inti dari mode jendela desktop, dan mengizinkan beberapa instance aplikasi Anda dapat sangat meningkatkan produktivitas pengguna.
Mulai Android 15, Anda dapat menggunakan
PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI. Dengan menetapkan properti ini di
AndroidManifest.xml, Anda menentukan bahwa UI sistem harus menyediakan opsi
(seperti tombol "Jendela Baru") agar aplikasi dapat diluncurkan dalam beberapa instance.
<application>
<property
android:name="android.window.PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI"
android:value="true" />
</application>
Catatan: Dalam mode jendela desktop dan lingkungan multi-aplikasi lainnya, tugas baru akan terbuka di jendela baru, jadi periksa kembali perjalanan pengguna setiap kali aplikasi Anda memulai beberapa tugas.
Mengelola instance aplikasi dengan gestur menarik
Dalam mode multi-aplikasi, pengguna dapat memulai instance aplikasi baru dengan menarik elemen UI (seperti tab atau dokumen) keluar dari jendela aplikasi. Pengguna juga dapat memindahkan elemen di antara berbagai instance aplikasi yang sama.
Mentransfer data dengan tarik lalu lepas
Untuk mengonfigurasi composable sebagai sumber tarik untuk tarik lalu lepas multi-instance
yang memungkinkan pengguna menarik konten ke instance lain aplikasi Anda, atau membuat
instance baru dengan melepas konten ke area kosong di layar—gunakan
pengubah dragAndDropSource. Dalam lambda-nya, tampilkan
DragAndDropTransferData, dengan meneruskan ClipData yang berisi data yang akan
ditransfer, dan flag untuk mengonfigurasi perilaku multi-instance.
Android 15 memperkenalkan dua flag utama untuk mode jendela bergaya desktop dan interaksi multi-instance:
DRAG_FLAG_GLOBAL_SAME_APPLICATION: Menunjukkan bahwa operasi tarik dapat melewati batas jendela (untuk beberapa instance dari aplikasi yang sama). SaatstartDragAndDrop()dipanggil dengan flag ini ditetapkan, hanya jendela yang terlihat milik aplikasi yang sama yang dapat berpartisipasi dalam operasi tarik dan menerima konten yang ditarik.
Modifier.dragAndDropSource { _ -> DragAndDropTransferData( clipData = ClipData.newPlainText("label", "Your data"), flags = View.DRAG_FLAG_GLOBAL_SAME_APPLICATION ) }
DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG: Memungkinkan pengguna memulai instance baru aplikasi Anda dengan meletakkan konten yang ditarik ke area kosong di layar, jika tidak ada jendela lain yang menangani peletakan.- Saat menggunakan flag ini, Anda harus menyediakan
IntentSendermenggunakanClipData.Item.Builder#setIntentSender(), yang digunakan sistem untuk meluncurkan aktivitas baru jika terjadi pelepasan yang tidak tertangani.
- Saat menggunakan flag ini, Anda harus menyediakan
Modifier.dragAndDropSource { _ -> val intent = Intent.makeMainActivity(activity.componentName).apply { putExtra("EXTRA_ITEM_ID", itemId) flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_MULTIPLE_TASK or Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT } val pendingIntent = PendingIntent.getActivity( activity, 0, intent, PendingIntent.FLAG_IMMUTABLE ) val data = ClipData( "Item $itemId", arrayOf(ClipDescription.MIMETYPE_TEXT_INTENT), ClipData.Item.Builder().setIntentSender(pendingIntent.intentSender).build() ) DragAndDropTransferData( clipData = data, flags = View.DRAG_FLAG_GLOBAL_SAME_APPLICATION or View.DRAG_FLAG_START_INTENT_SENDER_ON_UNHANDLED_DRAG, ) }
Menerima data yang ditransfer
Untuk menerima data dari instance lain, gunakan pengubah dragAndDropTarget.
Anda harus secara eksplisit meminta izin jika data berasal dari instance atau aplikasi lain.
Modifier.dragAndDropTarget( shouldStartDragAndDrop = { event -> event.toAndroidDragEvent().clipDescription.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN) }, target = object : DragAndDropTarget { override fun onDrop(event: DragAndDropEvent): Boolean { requestDragAndDropPermissions(activity, event.toAndroidDragEvent()) val clipData = event.toAndroidDragEvent().clipData val item = clipData?.getItemAt(0)?.text if (item != null) { // Process the dropped text item here } return item != null } } )
Langkah-langkah utama:
- Filter: Gunakan
shouldStartDragAndDropuntuk memeriksa apakah data yang masuk (jenis MIME) didukung. - Izin: Panggil
requestDragAndDropPermissions(event)untuk mengakses data. - Menangani: Ekstrak data dalam callback
onDrop.
Pengoptimalan tambahan
Menyesuaikan peluncuran aplikasi dan mentransisikan aplikasi dari mode jendela desktop ke layar penuh.
Menentukan ukuran dan posisi default
Tidak semua aplikasi, meskipun dapat diubah ukurannya, memerlukan jendela besar untuk menawarkan nilai kepada pengguna. Anda
dapat menggunakan metode ActivityOptions#setLaunchBounds() untuk menentukan ukuran
dan posisi default saat aktivitas diluncurkan.
Masuk ke layar penuh dari ruang desktop
Aplikasi dapat beralih ke layar penuh dengan memanggil Activity#requestFullScreenMode(). Metode
ini menampilkan aplikasi dalam layar penuh langsung dari mode jendela desktop.