Mulai dari Android 8.0 (API level 26), Android memungkinkan aktivitas diluncurkan dalam mode picture-in-picture (PiP). PiP adalah jenis khusus mode multi-aplikasi yang sebagian besar digunakan untuk pemutaran video. Dengan fitur ini, pengguna dapat menonton video di jendela kecil yang disematkan ke sudut layar sambil beralih antar-aplikasi atau menjelajahi konten di layar utama.
PiP memanfaatkan API multi-aplikasi yang tersedia di Android 7.0 untuk menyediakan jendela overlay video yang disematkan. Untuk menambahkan PiP ke aplikasi, Anda harus mendaftarkan aktivitas yang mendukung PiP, mengalihkan aktivitas ke mode PiP sesuai kebutuhan, dan memastikan elemen UI disembunyikan dan pemutaran video berlanjut saat aktivitas berlangsung dalam mode PiP.
Jendela PiP muncul di lapisan paling atas pada layar, di sudut yang dipilih oleh sistem.
Cara pengguna dapat berinteraksi dengan jendela PiP
Pengguna dapat menarik jendela PiP ke lokasi lain. Mulai Android 12, pengguna juga dapat:
Ketuk satu kali jendela untuk menampilkan tombol layar penuh, tombol tutup, tombol setelan, dan tindakan kustom yang disediakan oleh aplikasi Anda (misalnya, kontrol putar).
Ketuk dua kali jendela untuk beralih antara ukuran PiP saat ini dan ukuran PiP maksimum. Letakkan jendela dengan menariknya ke tepi kiri atau kanan; untuk membuka jendela, ketuk bagian yang terlihat dari jendela yang disembunyikan atau tarik.
Ubah ukuran jendela PiP menggunakan cubit untuk zoom.
Aplikasi mengontrol kapan aktivitas yang aktif memasuki mode PiP. Berikut beberapa contohnya:
Suatu aktivitas dapat memasuki mode PiP saat pengguna mengetuk tombol layar utama (dalam mode navigasi tombol) atau menggeser ke atas untuk beralih ke mode utama (dalam mode navigasi gestur). (Ini adalah cara Google Maps terus menampilkan rute saat pengguna menjalankan aktivitas lain secara bersamaan.)
Aplikasi dapat memindahkan video ke mode PiP saat pengguna kembali dari video untuk menjelajahi konten lain.
Aplikasi dapat mengalihkan video ke mode PiP saat pengguna menonton bagian akhir sebuah episode konten. Layar utama menampilkan informasi promosi atau ringkasan tentang episode berikutnya dalam serial.
Aplikasi dapat memberi pengguna cara mengantrekan konten tambahan saat menonton video. Video terus diputar dalam mode PiP sementara layar utama menampilkan aktivitas pemilihan konten.
Mendeklarasikan dukungan picture-in-picture
Secara default, sistem tidak otomatis mendukung PiP untuk aplikasi.
Jika menginginkan dukungan PiP di aplikasi, daftarkan aktivitas video
Anda dalam manifes dengan menetapkan
android:supportsPictureInPicture
ke true
. Selain itu, tentukan
bahwa aktivitas Anda menangani perubahan konfigurasi tata letak agar aktivitas
tidak diluncurkan kembali bila perubahan tata letak terjadi saat transisi mode PiP berlangsung.
<activity android:name="VideoActivity"
android:supportsPictureInPicture="true"
android:configChanges=
"screenSize|smallestScreenSize|screenLayout|orientation"
...
Mengalihkan aktivitas ke mode picture-in-picture
Untuk masuk ke mode picture-in-picture, aktivitas harus memanggil
enterPictureInPictureMode()
.
Misalnya, kode
berikut mengalihkan aktivitas ke mode PiP saat pengguna mengklik tombol khusus di UI aplikasi:
Kotlin
override fun onActionClicked(action: Action) { if (action.id.toInt() == R.id.lb_control_picture_in_picture) { activity?.enterPictureInPictureMode() return } }
Java
@Override public void onActionClicked(Action action) { if (action.getId() == R.id.lb_control_picture_in_picture) { getActivity().enterPictureInPictureMode(); return; } ... }
Anda mungkin ingin menyertakan logika yang mengalihkan aktivitas ke mode PiP, bukan ke
latar belakang. Misalnya, Google Maps beralih ke mode PiP jika
pengguna menekan tombol layar utama atau terbaru saat aplikasi dibuka. Anda dapat mengatasi kasus ini dengan mengganti onUserLeaveHint()
:
Kotlin
override fun onUserLeaveHint() { if (iWantToBeInPipModeNow()) { enterPictureInPictureMode() } }
Java
@Override public void onUserLeaveHint () { if (iWantToBeInPipModeNow()) { enterPictureInPictureMode(); } }
Membuat transisi ke mode PiP lebih lancar dari navigasi gestur
Mulai di Android 12, Anda dapat menggunakan
flag setAutoEnterEnabled
untuk memberikan transisi yang lebih lancar ke mode PiP saat menggeser ke atas dalam
mode navigasi gestur.
Untuk mengimplementasikan fitur ini:
Gunakan
setAutoEnterEnabled
untuk membuatPictureInPictureParams.Builder
, sebagai berikut:setPictureInPictureParams(new PictureInPictureParams.Builder() .setAspectRatio(aspectRatio) .setSourceRectHint(sourceRectHint) .setAutoEnterEnabled(true) .build());
Panggil
setPictureInPictureParams
menggunakan informasiPictureInPictureParams
terbaru lebih awal. Aplikasi tidak perlu menunggu callbackonUserLeaveHint
(seperti yang akan dilakukan di Android 11).Misalnya, aplikasi dapat memanggil
setPictureInPictureParams
pada pemutaran pertama dan pemutaran berikutnya jika rasio lebar tinggi diubah.Panggil
setAutoEnterEnabled(false)
jika perlu. Misalnya, aplikasi video mungkin tidak optimal untuk masuk ke mode PiP jika pemutaran saat ini dalam keadaan dijeda.
Menangani UI selama mode picture-in-picture
Saat aktivitas memasuki atau keluar dari mode picture-in-picture, sistem akan memanggil
Activity.onPictureInPictureModeChanged()
atau Fragment.onPictureInPictureModeChanged()
.
Anda harus mengganti callback ini untuk menggambar ulang elemen UI aktivitas. Perlu diingat bahwa dalam mode PiP, aktivitas ditampilkan di jendela kecil. Pengguna tidak dapat berinteraksi dengan elemen UI aplikasi Anda saat dalam mode PiP dan detail elemen UI kecil mungkin sulit dilihat. Aktivitas pemutaran video dengan UI yang minimal akan memberikan pengalaman pengguna terbaik.
Jika aplikasi Anda perlu memberikan tindakan kustom untuk PiP, lihat Menambahkan kontrol dalam dokumen ini. Hapus elemen UI lainnya sebelum aktivitas memasuki PiP dan pulihkan saat aktivitas kembali menjadi layar penuh:
Kotlin
override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean, newConfig: Configuration) { if (isInPictureInPictureMode) { // Hide the full-screen UI (controls, etc.) while in picture-in-picture mode. } else { // Restore the full-screen UI. } }
Java
@Override public void onPictureInPictureModeChanged (boolean isInPictureInPictureMode, Configuration newConfig) { if (isInPictureInPictureMode) { // Hide the full-screen UI (controls, etc.) while in picture-in-picture mode. } else { // Restore the full-screen UI. ... } }
Dukungan animasi yang lebih halus saat keluar dari mode PiP
Di Android 12, flag SourceRectHint
kini digunakan kembali untuk menerapkan animasi yang lebih halus saat keluar dari mode PiP.
Saat keluar, sistem akan membuat animasi menggunakan sourceRectHint
yang tersedia saat ini, baik Rect
asli yang digunakan untuk masuk ke mode PiP maupun
Rect
terbaru yang disediakan oleh aplikasi.
Untuk menerapkan fitur ini, update aplikasi Anda seperti berikut:
Lanjutkan untuk menyusun
PictureInPictureParams
dengansourceRectHint
danaspectRatio
untuk animasi entri yang lancar.Jika perlu, update
sourceRectHint
sebelum sistem memulai transisi keluar. Saat sistem akan keluar dari mode PiP, hierarki tampilan aktivitas diatur ke konfigurasi tujuannya (misalnya, layar penuh). Aplikasi dapat melampirkan pemroses perubahan tata letak ke tampilan root atau tampilan targetnya (seperti tampilan pemutar video) untuk mendeteksi peristiwa dan mengupdate sourceRectHint sebelum animasi dimulai.Kotlin
// Listener is called immediately after the user exits PiP but before animating. playerView.addOnLayoutChangeListener { _, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom -> if (left != oldLeft || right != oldRight || top != oldTop || bottom != oldBottom) { // The playerView's bounds changed, update the source hint rect to // reflect its new bounds. val sourceRectHint = Rect() playerView.getGlobalVisibleRect(sourceRectHint) setPictureInPictureParams( PictureInPictureParams.Builder() .setSourceRectHint(sourceRectHint) .build() ) } }
Java
// Listener is called right after the user exits PiP but before // animating. playerView.addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { if (left != oldLeft || right != oldRight || top != oldTop || bottom != oldBottom) { // The playerView’s bounds changed, update the source hint rect to // reflect its new bounds. final Rect sourceRectHint = new Rect(); playerView.getGlobalVisibleRect(sourceRectHint); setPictureInPictureParams( new PictureInPictureParams.Builder() .setSourceRectHint(sourceRectHint) .build()); } });
Menambahkan kontrol
Jendela PiP dapat menampilkan kontrol saat pengguna membuka menu jendela tersebut (dengan mengetuk jendela di perangkat seluler, atau memilih menu dari remote TV.)
Jika aplikasi memiliki sesi media aktif, maka kontrol putar, jeda, berikutnya, dan sebelumnya akan muncul.
Anda juga dapat menentukan tindakan kustom secara eksplisit dengan mem-build
PictureInPictureParams
dengan PictureInPictureParams.Builder.setActions()
sebelum memasuki mode PiP, lalu meneruskan parameter saat memasuki mode PiP menggunakan
enterPictureInPictureMode(android.app.PictureInPictureParams)
atau setPictureInPictureParams(android.app.PictureInPictureParams)
.
Hati-hati. Jika mencoba menambahkan selain
getMaxNumPictureInPictureActions()
, Anda hanya akan mendapatkan angka maksimumnya.
Menonaktifkan pengubahan ukuran konten non-video yang lancar
Android 12 menambahkan flag setSeamlessResizeEnabled
yang menyediakan animasi cross-fading yang jauh lebih lancar saat mengubah ukuran
konten non-video di jendela PiP. Sebelumnya, mengubah ukuran konten non-video di
jendela PiP dapat membuat artefak visual yang janggal.
Flag setSeamlessResizeEnabled
ditetapkan ke true
secara default untuk
kompatibilitas mundur. Untuk konten video, biarkan setelan ini ditetapkan pada true
dan untuk konten non-video, ubah ke false
.
Untuk menonaktifkan pengubahan ukuran konten non-video yang lancar:
setPictureInPictureParams(new PictureInPictureParams.Builder()
.setSeamlessResizeEnabled(false)
.build());
Melanjutkan pemutaran video saat dalam mode picture-in-picture
Saat aktivitas beralih ke PIP, sistem akan menempatkan aktivitas tersebut dalam
keadaan dijeda dan memanggil metode
onPause()
aktivitas. Pemutaran
video tidak akan dijeda dan video akan terus diputar jika aktivitas tersebut dijeda saat dalam mode PiP.
Di Android 7.0 dan yang lebih baru, Anda harus menjeda dan melanjutkan pemutaran video saat
sistem memanggil
onStop()
dan
onStart()
aktivitas. Dengan begitu,
Anda tidak perlu memeriksa apakah aplikasi dalam mode PiP di onPause() dan
dapat melanjutkan pemutaran secara eksplisit.
Jika Anda harus menjeda pemutaran dalam implementasi onPause()
, periksa mode PiP dengan memanggil isInPictureInPictureMode()
dan menangani pemutaran dengan benar, misalnya:
Kotlin
override fun onPause() { super.onPause() // If called while in PiP mode, do not pause playback if (isInPictureInPictureMode) { // Continue playback } else { // Use existing playback logic for paused Activity behavior. } }
Java
@Override public void onPause() { // If called while in PiP mode, do not pause playback if (isInPictureInPictureMode()) { // Continue playback ... } else { // Use existing playback logic for paused Activity behavior. ... } }
Saat aktivitas keluar dari mode PiP dan kembali ke mode layar penuh,
sistem akan melanjutkan aktivitas dan memanggil
metode onResume()
.
Menggunakan aktivitas pemutaran tunggal untuk mode picture-in-picture
Di aplikasi, pengguna mungkin memilih video baru saat menjelajahi konten di layar utama, selagi aktivitas pemutaran video berlangsung dalam mode PiP. Putar video baru dalam aktivitas pemutaran yang ada dalam mode layar penuh, bukan meluncurkan aktivitas baru yang dapat membingungkan pengguna.
Untuk memastikan aktivitas tunggal digunakan untuk permintaan pemutaran video dan
dialihkan ke dalam atau ke luar mode PiP sesuai keperluan, tetapkan
android:launchMode
aktivitas ke singleTask
dalam manifes:
<activity android:name="VideoActivity"
...
android:supportsPictureInPicture="true"
android:launchMode="singleTask"
...
Dalam aktivitas, ganti
onNewIntent()
dan tangani video baru, sehingga pemutaran video yang ada akan dihentikan, jika diperlukan.
Praktik terbaik
PiP mungkin dinonaktifkan di perangkat yang memiliki RAM rendah. Sebelum aplikasi menggunakan PiP, pastikan ketersediaannya dengan memanggil
hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)
.
PiP ditujukan untuk aktivitas yang memutar video dalam mode layar penuh. Saat mengalihkan aktivitas ke mode PiP, jangan tampilkan apa pun kecuali konten video. Pantau kapan aktivitas memasuki mode PiP, dan sembunyikan elemen UI sebagaimana dijelaskan dalam Menangani UI selama mode picture-in-picture.
Secara default, aktivitas tidak mendapatkan fokus input saat dalam mode PiP. Untuk
menerima peristiwa input saat dalam mode PiP, gunakan
MediaSession.setCallback()
.
Untuk informasi selengkapnya tentang penggunaan setCallback()
, lihat
Menampilkan kartu Now Playing.
Saat aplikasi dalam mode PiP, pemutaran video di jendela PiP dapat menyebabkan gangguan audio pada aplikasi lain, seperti aplikasi pemutar musik atau aplikasi penelusuran suara. Untuk menghindarinya, minta fokus audio saat Anda mulai memutar video, dan tangani notifikasi perubahan fokus audio, sebagaimana dijelaskan dalam Mengelola Fokus Audio. Jika Anda menerima notifikasi tentang hilangnya fokus audio saat dalam mode PiP, jeda atau hentikan pemutaran video.
Saat aplikasi akan memasuki PiP, perlu diketahui bahwa hanya aktivitas teratas yang akan memasuki Picture-in-Picture. Dalam situasi tertentu seperti pada perangkat multi-aplikasi, aktivitas
di bawah kini mungkin akan ditampilkan dan menjadi kembali terlihat bersama
aktivitas PiP. Anda harus menangani kasus ini sebagaimana mestinya, termasuk
aktivitas di bawah untuk mendapatkan callback onResume()
atau onPause()
. Pengguna
juga dapat berinteraksi dengan aktivitas tersebut. Misalnya, jika Anda memiliki
aktivitas daftar video yang ditampilkan dan aktivitas yang memutar video dalam mode PiP, pengguna
mungkin memilih video baru dari daftar dan aktivitas PiP akan diperbarui sebagaimana mestinya.
Kode contoh tambahan
Untuk mendownload aplikasi contoh yang ditulis di Android, lihat Contoh Picture-in-Picture . Untuk mendownload aplikasi contoh yang ditulis di Kotlin, lihat Contoh Android PictureInPicture (Kotlin).