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 digunakan untuk pemutaran video, panggilan video, dan navigasi. Fitur ini memungkinkan pengguna menyematkan jendela aktivitas yang ada ke sudut layar sambil berpindah-pindah 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 layar, di sudut yang dipilih oleh sistem.
PiP juga didukung di perangkat Android TV OS yang kompatibel yang menjalankan Android 14 (API level 34) atau yang lebih tinggi. 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 PiP maksimum atau minimum—misalnya, mengetuk dua kali jendela yang dimaksimalkan akan meminimalkannya, dan sebaliknya.
Sembunyikan jendela dengan menariknya ke tepi kiri atau kanan. Untuk membatalkan penyembunyian batas jendela, ketuk bagian jendela yang disembunyikan atau singkap.
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 ke atas untuk beralih ke mode utama. Ini adalah 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 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 PiP
Secara default, sistem tidak otomatis mendukung PiP untuk aplikasi. Jika Anda ingin
mendukung PiP di aplikasi, daftarkan aktivitas video dalam manifes dengan
menyetel android:supportsPictureInPicture ke true. Selain itu, tentukan bahwa
aktivitas Anda menangani perubahan konfigurasi tata letak sehingga aktivitas 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"
...
Menerapkan PiP dengan Jetpack
Gunakan library Picture-in-Picture Jetpack untuk menerapkan pengalaman picture-in-picture karena library ini menyederhanakan integrasi dan mengurangi masalah umum dalam aplikasi. Lihat aplikasi contoh platform kami untuk melihat contoh penggunaannya. Namun, jika Anda lebih suka menerapkan PiP menggunakan API platform, lihat dokumentasi berikut.
Mengalihkan aktivitas ke PiP
Mulai Android 12, Anda dapat mengalihkan aktivitas ke mode PiP dengan menetapkan
flag setAutoEnterEnabled ke true. Dengan setelan ini, aktivitas
akan otomatis beralih ke mode PiP sesuai kebutuhan tanpa harus memanggil
enterPictureInPictureMode() secara eksplisit di onUserLeaveHint. Hal ini juga memberikan manfaat tambahan berupa transisi yang jauh lebih lancar. Untuk mengetahui detailnya, lihat Membuat
transisi ke mode PiP lebih lancar dari navigasi gestur.
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:
override fun onActionClicked(action: Action) {
if (action.id.toInt() == R.id.lb_control_picture_in_picture) {
activity?.enterPictureInPictureMode()
return
}
}
Anda mungkin ingin menyertakan logika yang mengalihkan aktivitas ke mode PiP, bukan
masuk ke latar belakang. Misalnya, Google Maps beralih ke mode PiP jika
pengguna menekan tombol layar utama atau terbaru saat aplikasi dibuka. Anda dapat
menangkap kasus ini dengan mengganti onUserLeaveHint():
override fun onUserLeaveHint() {
if (iWantToBeInPipModeNow()) {
enterPictureInPictureMode()
}
}
Direkomendasikan: memberikan pengalaman transisi PiP yang rapi kepada pengguna
Android 12 menambahkan peningkatan visual yang signifikan pada transisi animasi antara jendela layar penuh dan PiP. Sebaiknya terapkan semua perubahan yang berlaku; setelah Anda melakukannya, perubahan ini akan otomatis diskalakan ke layar besar seperti perangkat foldable dan tablet tanpa perlu pekerjaan lebih lanjut.
Jika aplikasi Anda tidak menyertakan update yang berlaku, transisi PiP masih berfungsi, tetapi animasinya kurang rapi. Misalnya, transisi dari mode layar penuh ke mode PiP dapat menyebabkan jendela PiP menghilang selama transisi sebelum muncul kembali saat transisi selesai.
Perubahan ini mencakup hal berikut.
- Membuat transisi ke mode PiP lebih lancar dari navigasi gestur
- Menetapkan
sourceRectHintyang tepat untuk masuk dan keluar dari mode PiP - Menonaktifkan pengubahan ukuran yang lancar untuk konten non-video
Lihat contoh PictureInPicture Kotlin Android sebagai referensi untuk mengaktifkan pengalaman transisi yang lancar.
Membuat transisi ke mode PiP lebih lancar dari navigasi gestur
Mulai Android 12, flag setAutoEnterEnabled memberikan animasi yang jauh lebih lancar untuk transisi ke konten video dalam mode PiP menggunakan navigasi gestur—misalnya, saat menggeser ke atas untuk beralih ke layar utama dari layar penuh.
Selesaikan langkah-langkah berikut untuk melakukan perubahan ini:
- Gunakan
setAutoEnterEnableduntuk membuatPictureInPictureParams.Builder:
setPictureInPictureParams(PictureInPictureParams.Builder()
.setAspectRatio(aspectRatio)
.setSourceRectHint(sourceRectHint)
.setAutoEnterEnabled(true)
.build())
Note: When `setAutoEnterEnabled` is enabled, you don't need to explicitly
call [`enterPictureInPictureMode`][5] in [`onUserLeaveHint`][6].
Panggil
setPictureInPictureParamsmenggunakan informasiPictureInPictureParamsterbaru lebih awal. Aplikasi tidak menunggu callbackonUserLeaveHint(seperti yang akan dilakukan di Android 11).Misalnya, Anda mungkin ingin memanggil
setPictureInPictureParamspada pemutaran pertama dan pemutaran berikutnya jika rasio aspek diubah.Panggil
setAutoEnterEnabled(false), tetapi hanya jika diperlukan. Misalnya, Anda mungkin tidak ingin masuk ke mode PiP jika pemutaran saat ini dalam keadaan dijeda.
Menetapkan sourceRectHint yang tepat untuk masuk dan keluar dari mode PiP
Mulai dari pengenalan PiP di Android 8.0, setSourceRectHint
menunjukkan area aktivitas yang terlihat setelah transisi ke
picture-in-picture—misalnya, batas tampilan video di pemutar video.
Dengan Android 12, sistem menggunakan sourceRectHint untuk menerapkan animasi yang jauh lebih lancar
baik saat masuk maupun keluar dari mode PiP.
Untuk menyetel sourceRectHint dengan benar saat masuk dan keluar dari mode PiP:
- Buat
PictureInPictureParamsmenggunakan batas yang tepat sebagaisourceRectHint. Sebaiknya lampirkan juga pemroses perubahan tata letak ke pemutar video:
val mOnLayoutChangeListener =
OnLayoutChangeListener { v: View?, left: Int,
top: Int, right: Int, bottom: Int, oldLeft: Int, oldTop:
Int, oldRight: Int, oldBottom: Int ->
val sourceRectHint = Rect()
mYourVideoView.getGlobalVisibleRect(sourceRectHint)
val builder = PictureInPictureParams.Builder()
.setSourceRectHint(sourceRectHint)
setPictureInPictureParams(builder.build())
}
mYourVideoView.addOnLayoutChangeListener(mOnLayoutChangeListener)
- Jika perlu, update
sourceRectHintsebelum sistem memulai transisi keluar. Saat sistem akan keluar dari mode PiP, hierarki tampilan aktivitas ditata 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 memperbaruisourceRectHintsebelum animasi dimulai.
// 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()
)
}
}
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.
Untuk mengaktifkan pengubahan ukuran yang lancar untuk konten video:
setPictureInPictureParams(PictureInPictureParams.Builder()
.setSeamlessResizeEnabled(true)
.build())
Menangani UI selama PiP
Saat aktivitas masuk atau keluar dari mode Picture-in-Picture (PiP), sistem akan memanggil Activity.onPictureInPictureModeChanged() atau Fragment.onPictureInPictureModeChanged().
Android 15 memperkenalkan perubahan yang memastikan transisi yang lebih lancar saat memasuki mode PiP. Hal ini bermanfaat untuk aplikasi yang memiliki elemen UI yang dihamparkan di atas UI utamanya, yang masuk ke PiP.
Developer menggunakan callback onPictureInPictureModeChanged() untuk menentukan
logika yang mengalihkan visibilitas elemen UI yang dihamparkan. Callback ini
dipicu saat animasi masuk atau keluar PiP selesai. Mulai
Android 15, class PictureInPictureUiState menyertakan status baru.
Dengan status UI baru ini, aplikasi yang menargetkan Android 15 akan mengamati
callback Activity#onPictureInPictureUiStateChanged() yang dipanggil dengan
isTransitioningToPip() segera setelah animasi PiP dimulai. Ada
banyak elemen UI yang tidak relevan untuk aplikasi saat dalam mode PiP, misalnya, tampilan atau tata letak yang menyertakan informasi seperti saran, video
mendatang, rating, dan judul. Saat aplikasi beralih ke mode PiP, gunakan
callback onPictureInPictureUiStateChanged() untuk menyembunyikan elemen UI ini. Saat
aplikasi beralih ke mode layar penuh dari jendela PiP, gunakan
callback onPictureInPictureModeChanged() untuk memperlihatkan elemen ini, seperti yang ditunjukkan dalam
contoh berikut:
override fun onPictureInPictureUiStateChanged(pipState: PictureInPictureUiState) {
if (pipState.isTransitioningToPip()) {
// Hide UI elements.
}
}
override fun onPictureInPictureModeChanged(
isInPictureInPictureMode: Boolean,
newConfig: Configuration
) {
super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
if (!isInPictureInPictureMode) {
// Unhide UI elements.
}
}
Tombol visibilitas cepat elemen UI yang tidak relevan (untuk jendela PiP) ini membantu memastikan animasi masuk PiP yang lebih lancar dan bebas kedipan.
Ganti callback ini untuk menggambar ulang elemen UI aktivitas. Perlu diingat bahwa dalam mode PiP, aktivitas Anda ditampilkan di jendela kecil. Pengguna tidak dapat berinteraksi dengan elemen UI aplikasi Anda saat aplikasi 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 menyediakan tindakan kustom untuk PiP, lihat Menambahkan kontrol di halaman ini. Hapus elemen UI lainnya sebelum aktivitas Anda memasuki PiP dan pulihkan elemen tersebut saat aktivitas Anda kembali ke layar penuh.
Tambahkan 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, 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,
dan meneruskan parameter saat Anda memasuki mode PiP menggunakan
enterPictureInPictureMode(android.app.PictureInPictureParams) atau
setPictureInPictureParams(android.app.PictureInPictureParams). Hati-hati. Jika Anda mencoba menambahkan lebih dari getMaxNumPictureInPictureActions(),
Anda hanya akan mendapatkan jumlah maksimum.
Melanjutkan pemutaran video saat dalam mode PIP
Saat aktivitas Anda beralih ke PiP, sistem akan menempatkan aktivitas dalam status dijeda
dan memanggil metode onPause() aktivitas. Pemutaran video
tidak boleh dijeda dan harus terus diputar jika aktivitas dijeda saat
beralih ke mode PiP.
Di Android 7.0 (level API 24) dan yang lebih tinggi, Anda harus menjeda dan melanjutkan pemutaran video saat sistem memanggil onStop() dan onStart() aktivitas Anda. Dengan melakukan hal ini, Anda dapat menghindari keharusan memeriksa apakah aplikasi Anda
dalam mode PiP di onPause() dan melanjutkan pemutaran secara eksplisit.
Jika Anda belum menetapkan flag setAutoEnterEnabled ke true dan perlu
menjeda pemutaran dalam implementasi onPause(), periksa mode PiP dengan memanggil
isInPictureInPictureMode() dan tangani pemutaran dengan tepat. Contoh:
override fun onPause() {
super.onPause()
// If called while in PiP mode, don't pause playback.
if (isInPictureInPictureMode) {
// Continue playback.
} else {
// Use existing playback logic for paused activity behavior.
}
}
Saat aktivitas Anda beralih dari mode PiP kembali ke mode layar penuh, sistem
akan 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, sementara 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 satu aktivitas digunakan untuk permintaan pemutaran video dan beralih
ke atau keluar dari mode PiP sesuai kebutuhan, tetapkan android:launchMode aktivitas ke
singleTask dalam manifes Anda:
<activity android:name="VideoActivity"
...
android:supportsPictureInPicture="true"
android:launchMode="singleTask"
...
Dalam aktivitas Anda, ganti onNewIntent() dan tangani video baru,
dengan menghentikan pemutaran video yang ada jika diperlukan.
Mendukung PiP untuk aplikasi kamera
Untuk mengaktifkan PiP untuk aplikasi kamera, Anda harus memastikan kamera tetap aktif dalam
mode PiP dengan tidak menutup kamera saat onPause() dipanggil:
override fun onPause() {
super.onPause()
// Don't close the camera if the app is entering PiP mode
if (!isInPictureInPictureMode) {
closeCamera()
}
}
Seperti kasus penggunaan lainnya, sembunyikan elemen UI yang tidak penting (seperti kontrol dan overlay), dan tambahkan tindakan kustom untuk mengontrol kamera (misalnya, menghentikan perekaman atau membalik kamera).
Menghitung sourceRectHint untuk transisi yang lancar
Memberikan sourceRectHint yang akurat dengan koordinat layar yang tepat dari
jendela bidik kamera sangat penting untuk animasi masuk yang lancar. Anda bisa mendapatkan
batas dari tampilan pratinjau menggunakan getGlobalVisibleRect() sebagai berikut:
val previewView = findViewById<View>(R.id.preview_view)
val globalRect = Rect()
// Ensure the view is laid out before calling getGlobalVisibleRect() to get valid screen coordinates.
previewView.getGlobalVisibleRect(globalRect)
val params = PictureInPictureParams.Builder()
.setSourceRectHint(globalRect)
.build()
setPictureInPictureParams(params)
Pertimbangan tambahan
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 sembunyikan 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 kartu Now Playing.
Saat aplikasi Anda dalam mode PiP, pemutaran video di jendela PiP dapat menyebabkan gangguan audio 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 Fokus Audio. Jika Anda menerima notifikasi kehilangan fokus audio saat dalam mode PiP, jeda atau hentikan pemutaran video.
Saat aplikasi Anda akan memasuki PiP, perhatikan bahwa hanya aktivitas teratas yang memasuki
picture-in-picture. Dalam beberapa situasi seperti pada perangkat multi-aplikasi, aktivitas yang mendasarinya mungkin akan ditampilkan dan terlihat lagi
bersama dengan aktivitas PiP. Anda harus menangani kasus ini sebagaimana mestinya, termasuk
aktivitas yang mendasarinya mendapatkan callback onResume() atau onPause().
Pengguna juga dapat berinteraksi dengan aktivitas tersebut.
Misalnya, jika Anda menampilkan aktivitas daftar video dan aktivitas video yang diputar
dalam mode PiP, pengguna mungkin memilih video baru dari daftar dan
aktivitas PiP harus diperbarui.
Kode contoh tambahan
Untuk mendownload aplikasi contoh yang ditulis dalam Kotlin, lihat Contoh PictureInPicture Android (Kotlin).