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 akan muncul di lapisan paling atas layar, di sudut yang dipilih oleh sistem.
PiP juga didukung di perangkat OS Android TV yang kompatibel dan menjalankan Android 14 (level API 34) atau yang lebih baru. Meskipun ada banyak kesamaan, ada pertimbangan tambahan saat menggunakan PiP di TV.
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 maksimum atau ukuran PiP minimum—misalnya, mengetuk dua kali pada jendela yang dimaksimalkan meminimalkannya, dan hal sebaliknya juga berlaku.
Gabungkan jendela dengan menariknya ke tepi kiri atau kanan. Untuk membatalkan penyembunyian jendela, ketuk bagian yang terlihat dari jendela yang disembunyikan atau seret.
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 atau menggeser di layar beranda. Beginilah cara Google Maps terus menampilkan rute saat pengguna menjalankan aktivitas lain secara bersamaan.
Aplikasi Anda dapat memindahkan video ke mode PiP saat pengguna kembali dari video untuk menjelajahi konten lainnya.
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 saat layar utama menampilkan aktivitas pemilihan konten.
Mendeklarasikan dukungan PiP
Secara default, sistem tidak otomatis mendukung PiP untuk aplikasi. Jika Anda ingin
mendukung PiP di aplikasi, daftarkan aktivitas video Anda dalam manifes dengan
menyetel android:supportsPictureInPicture
ke true
. Selain itu, tentukan bahwa
aktivitas Anda menangani perubahan konfigurasi tata letak
sehingga aktivitas Anda tidak
diluncurkan kembali saat perubahan tata letak terjadi selama transisi mode PiP.
<activity android:name="VideoActivity"
android:supportsPictureInPicture="true"
android:configChanges=
"screenSize|smallestScreenSize|screenLayout|orientation"
...
Mengalihkan aktivitas ke PiP
Mulai Android 12, Anda dapat mengalihkan aktivitas ke mode PiP dengan menyetelnya
flag setAutoEnterEnabled
ke true
. Dengan setelan ini, aktivitas
otomatis beralih ke mode PiP sesuai kebutuhan tanpa harus memanggilnya secara eksplisit
enterPictureInPictureMode()
di onUserLeaveHint
. Fitur ini memiliki
manfaat tambahan yaitu menyediakan
transisi yang jauh lebih halus. Untuk mengetahui detailnya, lihat Make
lebih lancar dari navigasi gestur ke mode PiP.
Jika Anda menargetkan Android 11 atau yang lebih rendah, aktivitas harus memanggil
enterPictureInPictureMode()
untuk beralih ke mode PiP. 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
untuk beralih 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(); } }
Direkomendasikan: berikan pengalaman transisi PiP yang bagus kepada pengguna
Android 12 menambahkan peningkatan tampilan yang signifikan pada transisi animasi antara jendela layar penuh dan PiP. Sebaiknya Anda menerapkan semua perubahan yang berlaku; setelah Anda melakukannya, perubahan ini secara otomatis perangkat layar besar seperti perangkat foldable dan tablet tanpa pekerjaan lebih lanjut.
Jika aplikasi Anda tidak menyertakan update yang berlaku, transisi PiP akan tetap fungsional, tetapi animasinya kurang rapi. Misalnya, mengubah dari layar penuh ke mode PiP dapat menyebabkan jendela PiP menghilang selama sebelum muncul kembali saat transisi selesai.
Perubahan ini mencakup hal-hal berikut.
- Membuat transisi ke mode PiP lebih lancar dari navigasi gestur
- Menyetel
sourceRectHint
yang tepat untuk masuk dan keluar dari mode PiP - Menonaktifkan pengubahan ukuran yang lancar untuk konten non-video
Lihat panduan Android Contoh PictureInPicture Kotlin sebagai referensi untuk memungkinkan pengalaman transisi yang sempurna.
Membuat transisi ke mode PiP lebih lancar dari navigasi gestur
Mulai Android 12, flag setAutoEnterEnabled
menyediakan banyak
animasi yang lebih halus untuk beralih ke konten video dalam mode PiP menggunakan gestur
navigasi—misalnya, saat menggeser ke atas untuk kembali ke layar utama dari layar penuh.
Selesaikan langkah-langkah berikut untuk melakukan perubahan ini dan lihat contoh ini untuk mengetahui referensi:
Menggunakan
setAutoEnterEnabled
untuk membuatPictureInPictureParams.Builder
:Kotlin
setPictureInPictureParams(PictureInPictureParams.Builder() .setAspectRatio(aspectRatio) .setSourceRectHint(sourceRectHint) .setAutoEnterEnabled(true) .build())
Java
setPictureInPictureParams(new PictureInPictureParams.Builder() .setAspectRatio(aspectRatio) .setSourceRectHint(sourceRectHint) .setAutoEnterEnabled(true) .build());
Panggil
setPictureInPictureParams
menggunakan informasiPictureInPictureParams
terbaru lebih awal. Aplikasi tidak menunggu CallbackonUserLeaveHint
(seperti yang akan dilakukan di Android 11).Misalnya, Anda dapat memanggil
setPictureInPictureParams
di bagian pemutaran pertama dan pemutaran berikutnya jika rasio aspek diubah.Panggil
setAutoEnterEnabled(false)
, tetapi hanya jika diperlukan. Misalnya, sebaiknya jangan masukkan PiP jika pemutaran saat ini sedang status.
Setel sourceRectHint
yang sesuai untuk masuk dan keluar dari mode PiP
Dimulai dengan pengenalan PiP di Android 8.0, setSourceRectHint
menunjukkan area aktivitas yang terlihat setelah transisi ke
picture-in-picture—misalnya, batas jumlah tontonan video di pemutar video.
Dengan Android 12, sistem menggunakan sourceRectHint
untuk mengimplementasikan antarmuka yang jauh lebih lancar
animasi saat masuk maupun keluar dari mode PiP.
Guna menyetel sourceRectHint
dengan benar untuk masuk dan keluar dari mode PiP:
Membuat
PictureInPictureParams
menggunakan batas yang sesuai sebagaisourceRectHint
. Sebaiknya Anda juga melampirkan pemroses perubahan tata letak ke pemutar video:Kotlin
val mOnLayoutChangeListener = OnLayoutChangeListener { v: View?, oldLeft: Int, oldTop: Int, oldRight: Int, oldBottom: Int, newLeft: Int, newTop: Int, newRight: Int, newBottom: Int -> val sourceRectHint = Rect() mYourVideoView.getGlobalVisibleRect(sourceRectHint) val builder = PictureInPictureParams.Builder() .setSourceRectHint(sourceRectHint) setPictureInPictureParams(builder.build()) } mYourVideoView.addOnLayoutChangeListener(mOnLayoutChangeListener)
Java
private final View.OnLayoutChangeListener mOnLayoutChangeListener = (v, oldLeft, oldTop, oldRight, oldBottom, newLeft, newTop, newRight, newBottom) -> { final Rect sourceRectHint = new Rect(); mYourVideoView.getGlobalVisibleRect(sourceRectHint); final PictureInPictureParams.Builder builder = new PictureInPictureParams.Builder() .setSourceRectHint(sourceRectHint); setPictureInPictureParams(builder.build()); }; mYourVideoView.addOnLayoutChangeListener(mOnLayoutChangeListener);
Jika perlu, update
sourceRectHint
sebelum sistem memulai keluar dari transisi. Saat sistem akan keluar dari mode PiP, aktivitas hierarki tampilan ditetapkan ke konfigurasi tujuannya (misalnya, layar penuh). Aplikasi dapat melampirkan pemroses perubahan tata letak ke tampilan root-nya atau tampilan target (seperti tampilan pemutar video) untuk mendeteksi peristiwa dan perbaruisourceRectHint
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()); } });
Menonaktifkan pengubahan ukuran konten non-video yang lancar
Android 12 menambahkan flag setSeamlessResizeEnabled
, yang memberikan
animasi cross-fading yang lebih halus saat mengubah ukuran konten non-video di PiP
jendela. Sebelumnya, mengubah ukuran konten non-video di jendela PiP dapat membuat
artefak visual yang
mengagumkan.
Untuk menonaktifkan pengubahan ukuran konten non-video yang lancar:
Kotlin
setPictureInPictureParams(PictureInPictureParams.Builder() .setSeamlessResizeEnabled(false) .build())
Java
setPictureInPictureParams(new PictureInPictureParams.Builder() .setSeamlessResizeEnabled(false) .build());
Menangani UI selama PiP
Saat aktivitas memasuki atau keluar dari mode PiP, 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 perlu memberikan tindakan kustom untuk PiP, lihat Menambahkan di halaman 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 PiP 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 PiP mode. } else { // Restore the full-screen UI. ... } }
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 media aktif sesi, lalu putar, kontrol jeda, berikutnya, dan sebelumnya akan muncul.
Anda juga dapat menentukan tindakan kustom secara eksplisit dengan membangun
PictureInPictureParams
dengan
PictureInPictureParams.Builder.setActions()
sebelum memasuki mode PiP, dan teruskan 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.
Melanjutkan pemutaran video saat dalam PiP
Saat aktivitas beralih ke PiP, sistem akan menempatkan aktivitas tersebut di bagian yang dijeda
dan memanggil metode
Metode onPause()
. Video
pemutaran tidak boleh dijeda dan sebagai gantinya terus diputar jika aktivitas
dijeda saat beralih ke 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 melakukannya,
Anda dapat menghindari perlunya memeriksa apakah aplikasi
dalam mode PiP di onPause()
dan
melanjutkan pemutaran secara eksplisit.
Jika Anda belum menetapkan tanda setAutoEnterEnabled
ke true
dan Anda harus
menjeda pemutaran dalam implementasi onPause()
, periksa mode PiP dengan memanggil
isInPictureInPictureMode()
dan tangani pemutaran dengan tepat. Contoh:
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 Anda keluar dari mode PiP kembali ke mode layar penuh, sistem
melanjutkan aktivitas Anda dan memanggil
Metode onResume()
.
Menggunakan aktivitas pemutaran tunggal untuk PiP
Di aplikasi Anda, pengguna mungkin memilih video baru saat menjelajahi konten di layar utama, saat aktivitas pemutaran video berada dalam mode PiP. Putar video baru dalam aktivitas pemutaran yang ada dalam mode layar penuh, bukan meluncurkan aktivitas baru yang mungkin membingungkan pengguna.
Untuk memastikan aktivitas tunggal digunakan untuk permintaan pemutaran video dan dialihkan
masuk atau keluar dari mode PiP sesuai kebutuhan, setel android:launchMode
aktivitas ke
singleTask
dalam manifes Anda:
<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. Lacak kapan aktivitas Anda memasuki mode PiP dan menyembunyikan elemen UI, seperti yang dijelaskan dalam Menangani UI selama PiP.
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 Now Playing
kartu.
Saat aplikasi dalam mode PiP, pemutaran video di jendela PiP dapat menyebabkan audio gangguan dengan aplikasi lain, seperti aplikasi pemutar musik atau aplikasi penelusuran suara. Untuk menghindari hal ini, minta fokus audio saat Anda mulai memutar video, dan tangani notifikasi perubahan fokus audio, seperti yang dijelaskan dalam Mengelola Audio Fokus. Jika Anda menerima notifikasi hilangnya fokus audio saat dalam mode PiP, menjeda atau menghentikan pemutaran video.
Saat aplikasi akan memasuki PiP, perhatikan 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 dalam Kotlin, lihat Contoh PictureInPicture Android (Kotlin).