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 organisasi layar dengan mode jendela desktop 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.
- Header bar baru yang dapat disesuaikan menghiasi bagian atas setiap jendela dengan kontrol seperti minimalkan dan maksimalkan.
Secara default, aplikasi akan dibuka dalam mode 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 tuas jendela saat Anda mengetuk atau mengklik tuas atau menggunakan pintasan keyboard Meta key (Windows, Command, or Search) + Ctrl + Down.
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 keluar dari mode jendela desktop dan menjalankan aplikasi dalam mode layar penuh lagi.
Untuk kembali ke mode jendela desktop, ketuk atau klik kartu ruang desktop di layar Aplikasi Terbaru.
Mengoptimalkan tata letak aplikasi untuk lingkungan seperti desktop
Desain untuk pengalaman desktop dapat berbeda secara signifikan dari desain seluler karena peningkatan ruang layar, presisi input mouse dan keyboard, serta ekspektasi produktivitas tinggi.
Jetpack WindowManager menyediakan API yang berpendapat 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 pengubahan ukuran dan kompatibilitas
Dalam mode jendela desktop, aplikasi dengan orientasi terkunci dapat diubah ukurannya secara bebas. Artinya, meskipun aktivitas terkunci ke orientasi potret,pengguna tetap dapat mengubah ukuran aplikasi ke jendela orientasi lanskap.
UI aplikasi yang dideklarasikan sebagai tidak dapat diubah ukurannya (yaitu, resizeableActivity = false) akan diskalakan 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 akan melakukan hardcode atau membuat asumsi yang menyebabkan kesalahan perhitungan orientasi atau rasio aspek pratinjau atau gambar yang diambil sehingga gambar menjadi terentang, menyamping, atau terbalik.
Hingga aplikasi siap menerapkan jendela bidik kamera yang sepenuhnya responsif, perlakuan khusus ini memberikan pengalaman pengguna yang lebih dasar yang mengurangi efek asumsi yang salah.
Untuk mempelajari mode kompatibilitas untuk aplikasi kamera lebih lanjut, lihat Mode kompatibilitas perangkat.
Inset header yang dapat disesuaikan
Semua aplikasi yang berjalan dalam mode jendela desktop memiliki header bar, bahkan dalam mode imersif. Anda dapat menyesuaikan header bar ini untuk mencegah konten aplikasi Anda terhalang dan menggambar elemen UI kustom langsung ke ruang header.
Penerapan
Untuk menggambar konten kustom di header bar, langkah pertama adalah membuat latar belakang header bar menjadi transparan. Anda dapat melakukannya dengan menggunakan the
APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND flag with the
WindowInsetsController.
window.insetsController?.setSystemBarsAppearance( WindowInsetsController.APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND, WindowInsetsController.APPEARANCE_TRANSPARENT_CAPTION_BAR_BACKGROUND )
Setelah header bar transparan, Anda dapat menata gaya area header agar sesuai dengan desain aplikasi Anda. Gunakan WindowInsets.isCaptionBarVisible untuk mendeteksi apakah header bar
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 header bar sistem, sehingga membantu latar belakang kustom Anda mengisi area keterangan tanpa melakukan hardcode nilai piksel.WindowInsets.captionBar: Menyediakan dimensi untuk kontrol mode jendela desktop 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 caption bar, seperti tab—seperti di Google Chrome—kolom penelusuran, atau avatar profil.
Antarmuka pengguna
Untuk menghindari tumpang tindih UI dengan tombol sistem, Android 15 menyediakan metode
WindowInsets#getBoundingRects(). Metode ini menampilkan daftar objek
Rect yang mewakili area yang ditempati oleh elemen sistem. Ruang yang tersisa di caption bar adalah zona aman tempat Anda dapat menempatkan konten kustom dengan aman.
Beralih tampilan elemen keterangan 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 multi-tasking dan multi-instance
Multi-tasking adalah inti dari mode jendela desktop, dan mengizinkan beberapa instance aplikasi Anda dapat 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 "New Window") 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 dibuka di jendela baru, jadi periksa kembali perjalanan pengguna setiap kali aplikasi Anda memulai beberapa tugas.
Mengelola instance aplikasi dengan gestur tarik
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 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 aplikasi Anda yang lain, atau membuat
baru instance dengan melepaskan konten ke area layar yang kosong—gunakan
dragAndDropSource pengubah. Dalam lambdanya, tampilkan
DragAndDropTransferData, teruskan ClipData yang berisi data yang akan
ditransfer, dan flag untuk mengonfigurasi perilaku multi-instance.
Android 15 memperkenalkan dua flag utama untuk mode jendela gaya desktop dan interaksi multi-instance:
DRAG_FLAG_GLOBAL_SAME_APPLICATION: Menunjukkan bahwa operasi tarik dapat melintasi batas jendela (untuk beberapa instance aplikasi yang sama). SaatstartDragAndDrop()dipanggil dengan flag ini ditetapkan, hanya jendela yang terlihat yang termasuk dalam 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 aplikasi baru dengan melepaskan konten yang ditarik ke area layar yang kosong, jika tidak ada jendela lain yang menangani pelepasan.- 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 yang berbeda.
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 masuk (jenis MIME) didukung. - Izin: Panggil
requestDragAndDropPermissions(event)untuk mengakses data. - Penanganan: Ekstrak data dalam
onDropcallback.
Pengoptimalan tambahan
Sesuaikan peluncuran aplikasi dan transisi 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 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 masuk ke layar penuh dengan memanggil Activity#requestFullScreenMode(). Metode ini menampilkan aplikasi dalam mode layar penuh langsung dari mode jendela desktop.