Pencere içinde pencere (PiP) özelliğini kullanma

Compose yöntemini deneyin
Jetpack Compose, Android için önerilen kullanıcı arayüzü araç setidir. Compose'da pencere içinde pencere özelliğini nasıl destekleyeceğinizi öğrenin.

Android 8.0 (API düzeyi 26) sürümünden itibaren Android, etkinliklerin pencere içinde pencere (PIP) modunda başlatılmasına izin verir. PiP, video oynatma, görüntülü görüşme ve navigasyon için kullanılan özel bir çoklu pencere modudur. Kullanıcının, uygulamalar arasında gezinirken veya ana ekrandaki içeriklere göz atarken mevcut etkinlik penceresini ekranın bir köşesine sabitlemesine olanak tanır.

PiP, sabitlenmiş video yer paylaşımı penceresini sağlamak için Android 7.0'da sunulan çok pencereli API'lerden yararlanır. Uygulamanıza PiP eklemek için PiP'yi destekleyen etkinliklerinizi kaydetmeniz, etkinliğinizi gerektiğinde PiP moduna geçirmeniz ve etkinlik PiP modundayken kullanıcı arayüzü öğelerinin gizlendiğinden ve video oynatmanın devam ettiğinden emin olmanız gerekir.

PiP penceresi, ekranın en üst katmanında, sistem tarafından seçilen bir köşede görünür.

PiP, Android 14 (API düzeyi 34) veya sonraki sürümleri çalıştıran uyumlu Android TV OS cihazlarda da desteklenir. Birçok benzerlik olsa da TV'de PiP kullanırken dikkat edilmesi gereken ek noktalar vardır.

Kullanıcılar PiP penceresiyle nasıl etkileşim kurabilir?

Kullanıcılar PiP penceresini başka bir konuma sürükleyebilir. Android 12'den itibaren kullanıcılar şunları da yapabilir:

  • Pencereye bir kez dokunarak tam ekran açma/kapatma düğmesini, kapatma düğmesini, ayarlar düğmesini ve uygulamanız tarafından sağlanan özel işlemleri (ör. oynatma kontrolleri) görüntüleyebilirsiniz.

  • Pencereye iki kez dokunarak mevcut PiP boyutu ile maksimum veya minimum PiP boyutu arasında geçiş yapabilirsiniz. Örneğin, ekranı kaplayan bir pencereye iki kez dokunduğunuzda pencere simge durumuna küçülür. Bunun tersi de geçerlidir.

  • Pencereyi sol veya sağ kenara sürükleyerek gizleyin. Pencereyi gizli durumdan çıkarmak için gizli pencerenin görünen kısmına dokunun veya pencereyi dışarı sürükleyin.

  • PiP penceresini iki parmağınızı yakınlaştırarak yeniden boyutlandırın.

Mevcut etkinliğin PiP moduna ne zaman gireceğini uygulamanız kontrol eder. Aşağıda bazı örnekler verilmiştir:

  • Kullanıcı, ana sayfa düğmesine dokunduğunda veya yukarı kaydırarak ana sayfaya gittiğinde etkinlik, PiP moduna girebilir. Google Haritalar, kullanıcı aynı anda başka bir etkinlik yürütürken yol tariflerini bu şekilde göstermeye devam eder.

  • Uygulamanız, kullanıcı diğer içeriklere göz atmak için videodan geri gittiğinde videoyu PiP moduna geçirebilir.

  • Uygulamanız, kullanıcı bir içeriğin bölüm sonunu izlerken videoyu PiP moduna geçirebilir. Ana ekranda, dizinin bir sonraki bölümüyle ilgili tanıtım veya özet bilgileri gösterilir.

  • Uygulamanız, kullanıcıların video izlerken ek içerikleri sıraya eklemesine olanak tanıyabilir. Ana ekranda içerik seçme etkinliği gösterilirken video, PiP modunda oynatılmaya devam eder.

PiP desteğini bildirme

Sistem, uygulamalar için PiP'yi varsayılan olarak otomatik şekilde desteklemez. Uygulamanızda PiP'yi desteklemek istiyorsanız android:supportsPictureInPicture değerini true olarak ayarlayarak video etkinliğinizi manifest dosyanıza kaydedin. Ayrıca, PiP modu geçişleri sırasında düzen değişiklikleri gerçekleştiğinde etkinliğinizin yeniden başlatılmaması için etkinliğinizin düzen yapılandırması değişikliklerini işlediğini belirtin.

<activity android:name="VideoActivity"
    android:supportsPictureInPicture="true"
    android:configChanges=
        "screenSize|smallestScreenSize|screenLayout|orientation"
    ...

Jetpack ile PiP'yi uygulama

Entegrasyonu kolaylaştırdığı ve yaygın uygulama içi sorunları azalttığı için Jetpack pencere içinde pencere kitaplığını kullanarak pencere içinde pencere deneyimini uygulayın. Kullanım örneği için platform örnek uygulamamıza bakın. Ancak, platform API'lerini kullanarak PiP'yi uygulamayı tercih ederseniz aşağıdaki belgelere bakın.

Etkinliğinizi PiP'ye geçirme

Android 12'den itibaren setAutoEnterEnabled işaretini true olarak ayarlayarak etkinliğinizi PiP moduna geçirebilirsiniz. Bu ayar sayesinde bir etkinlik, onUserLeaveHint içinde enterPictureInPictureMode() yöntemini açıkça çağırmaya gerek kalmadan gerektiğinde otomatik olarak PiP moduna geçer. Bu sayede geçişler de çok daha sorunsuz olur. Ayrıntılar için Hareketle gezinmeden PiP moduna geçişleri daha sorunsuz hale getirme başlıklı makaleyi inceleyin.

Android 11 veya önceki sürümleri hedefliyorsanız bir etkinliğin PiP moduna geçmek için enterPictureInPictureMode() yöntemini çağırması gerekir. Örneğin, aşağıdaki kod, kullanıcı uygulamanın kullanıcı arayüzündeki özel bir düğmeyi tıkladığında bir etkinliği PiP moduna geçirir:

override fun onActionClicked(action: Action) {
    if (action.id.toInt() == R.id.lb_control_picture_in_picture) {
        activity?.enterPictureInPictureMode()
        return
    }
}

Arka plana geçmek yerine bir etkinliği PiP moduna geçiren mantığı eklemek isteyebilirsiniz. Örneğin, uygulama gezinme modundayken kullanıcı ana sayfa veya son kullanılanlar düğmesine basarsa Google Haritalar, PiP moduna geçer. onUserLeaveHint() yöntemini geçersiz kılarak bu durumu yakalayabilirsiniz:

override fun onUserLeaveHint() {
    if (iWantToBeInPipModeNow()) {
        enterPictureInPictureMode()
    }
}

Önerilen: Kullanıcılara sorunsuz bir PiP geçiş deneyimi sunma

Android 12, tam ekran ve PiP pencereleri arasındaki animasyonlu geçişlerde önemli kozmetik iyileştirmeler yaptı. Geçerli tüm değişiklikleri uygulamanızı önemle tavsiye ederiz. Bu değişiklikleri uyguladıktan sonra, katlanabilir cihazlar ve tabletler gibi büyük ekranlara otomatik olarak ölçeklendirilir ve başka bir işlem yapmanız gerekmez.

Uygulamanızda geçerli güncellemeler yoksa PiP geçişleri çalışmaya devam eder ancak animasyonlar daha az akıcı olur. Örneğin, tam ekrandan PiP moduna geçiş yaparken PiP penceresi geçiş sırasında kaybolabilir ve geçiş tamamlandığında tekrar görünebilir.

Bu değişiklikler aşağıdakileri içerir.

  • Hareketle gezinmeden PiP moduna geçişi daha sorunsuz hale getirme
  • Pencere içinde pencere moduna girip çıkmak için uygun bir sourceRectHint ayarlama
  • Video olmayan içerikler için sorunsuz yeniden boyutlandırmayı devre dışı bırakma

Sorunsuz bir geçiş deneyimi sağlamak için Android Kotlin PictureInPicture örneğine bakın.

Hareketle gezinmeden PiP moduna geçişleri daha sorunsuz hale getirme

Android 12'den itibaren setAutoEnterEnabled işareti, hareketle gezinme kullanarak PiP modunda video içeriğine geçiş için çok daha akıcı animasyonlar sağlar (ör. tam ekrandan ana ekrana geçmek için yukarı kaydırırken).

Bu değişikliği yapmak için aşağıdaki adımları uygulayın:

  1. PictureInPictureParams.Builder oluşturmak için setAutoEnterEnabled kullanın:
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].
  1. setPictureInPictureParams yöntemini güncel PictureInPictureParams ile erken çağırın. Uygulama, onUserLeaveHint geri çağırma işlevini beklemez (Android 11'de olduğu gibi).

    Örneğin, ilk oynatmada ve en boy oranı değişirse sonraki oynatmalarda setPictureInPictureParams yöntemini çağırmak isteyebilirsiniz.

  2. setAutoEnterEnabled(false) ile görüşün ancak yalnızca gerektiğinde. Örneğin, mevcut oynatma duraklatılmış durumdaysa PiP'ye girmek istemeyebilirsiniz.

Pencere içinde pencere moduna girmek ve bu moddan çıkmak için uygun bir sourceRectHint ayarlayın.

Android 8.0'da PIP'nin kullanıma sunulmasıyla birlikte setSourceRectHint, pencere içinde pencere moduna geçişten sonra görünen etkinlik alanını (ör. video oynatıcıdaki video görüntüleme sınırları) gösterir.

Android 12'de sistem, PiP moduna girerken ve çıkarken çok daha akıcı bir animasyon uygulamak için sourceRectHint kullanır.

Pencere içinde pencere moduna girerken ve bu moddan çıkarken sourceRectHint değerini doğru şekilde ayarlamak için:

  1. sourceRectHint olarak uygun sınırları kullanarak PictureInPictureParams oluşturun. Video oynatıcıya bir düzen değişikliği dinleyicisi de eklemenizi öneririz:
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)
  1. Gerekirse sistem çıkış geçişini başlatmadan önce sourceRectHint değerini güncelleyin. Sistem, PiP modundan çıkmak üzereyken etkinliğin görünüm hiyerarşisi, hedef yapılandırmasına (ör. tam ekran) göre düzenlenir. Uygulama, etkinliği algılamak ve animasyon başlamadan önce sourceRectHint değerini güncellemek için kök görünümüne veya hedef görünümüne (video oynatıcı görünümü gibi) bir düzen değişikliği dinleyicisi ekleyebilir.
// 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()
        )
    }
}

Video olmayan içerikler için sorunsuz yeniden boyutlandırmayı devre dışı bırakma

Android 12, PiP penceresinde video olmayan içerikleri yeniden boyutlandırırken çok daha akıcı bir çapraz geçiş animasyonu sağlayan setSeamlessResizeEnabled işaretini ekler. Daha önce, PiP penceresindeki video dışı içeriğin yeniden boyutlandırılması, rahatsız edici görsel kusurlara neden olabiliyordu.

Video içeriği için sorunsuz yeniden boyutlandırmayı etkinleştirmek üzere:

setPictureInPictureParams(PictureInPictureParams.Builder()
    .setSeamlessResizeEnabled(true)
    .build())

PiP sırasında kullanıcı arayüzünü yönetme

Etkinlik, pencere içinde pencere (PiP) moduna girdiğinde veya bu moddan çıktığında sistem Activity.onPictureInPictureModeChanged() ya da Fragment.onPictureInPictureModeChanged() yöntemini çağırır.

Android 15, PiP moduna girerken daha sorunsuz bir geçiş sağlayan değişiklikler sunar. Bu, ana kullanıcı arayüzünün üzerinde kullanıcı arayüzü öğeleri bulunan uygulamalar için faydalıdır. Bu öğeler PiP'ye girer.

Geliştiriciler, yer paylaşımlı kullanıcı arayüzü öğelerinin görünürlüğünü açıp kapatan mantığı tanımlamak için onPictureInPictureModeChanged() geri çağırma işlevini kullanır. Bu geri çağırma, PiP'ye giriş veya çıkış animasyonu tamamlandığında tetiklenir. Android 15'ten itibaren PictureInPictureUiState sınıfı yeni bir durum içerir.

Bu yeni kullanıcı arayüzü durumuyla, Android 15'i hedefleyen uygulamalar, PiP animasyonu başlar başlamaz Activity#onPictureInPictureUiStateChanged() geri çağırma işlevinin isTransitioningToPip() ile çağrıldığını görür. Uygulama PiP modundayken alakalı olmayan birçok kullanıcı arayüzü öğesi vardır. Örneğin, öneriler, gelecek video, derecelendirmeler ve başlıklar gibi bilgileri içeren görünümler veya düzenler. Uygulama PiP moduna geçtiğinde bu kullanıcı arayüzü öğelerini gizlemek için onPictureInPictureUiStateChanged() geri çağırma işlevini kullanın. Uygulama, PiP penceresinden tam ekran moduna geçtiğinde bu öğeleri göstermek için aşağıdaki örneklerde gösterildiği gibi onPictureInPictureModeChanged() geri çağırma işlevini kullanın:

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.
    }
}

Alakasız kullanıcı arayüzü öğelerinin (PiP penceresi için) görünürlüğünü hızlıca açıp kapatabilme özelliği, PiP'ye giriş animasyonunun daha sorunsuz ve titreme olmadan gerçekleşmesini sağlar.

Etkinliğin kullanıcı arayüzü öğelerini yeniden çizmek için bu geri çağırmaları geçersiz kılın. PiP modunda etkinliğinizin küçük bir pencerede gösterildiğini unutmayın. Uygulama PiP modundayken kullanıcılar uygulamanızın kullanıcı arayüzü öğeleriyle etkileşimde bulunamaz ve küçük kullanıcı arayüzü öğelerinin ayrıntılarını görmek zor olabilir. Minimum kullanıcı arayüzüne sahip video oynatma etkinlikleri en iyi kullanıcı deneyimini sağlar.

Uygulamanızın PiP için özel işlemler sağlaması gerekiyorsa bu sayfadaki Kontrol ekleme bölümüne bakın. Etkinliğiniz PiP moduna girmeden önce diğer kullanıcı arayüzü öğelerini kaldırın ve etkinliğiniz tekrar tam ekran olduğunda bunları geri yükleyin.

Kontrol ekle

PiP penceresi, kullanıcı pencerenin menüsünü açtığında (mobil cihazda pencereye dokunarak veya TV uzaktan kumandasından menüyü seçerek) kontrolleri gösterebilir.

Bir uygulamanın etkin bir medya oturumu varsa oynatma, duraklatma, sonraki ve önceki kontrolleri görünür.

Ayrıca, PiP moduna girmeden önce PictureInPictureParams.Builder.setActions() ile PictureInPictureParams oluşturarak özel işlemleri açıkça belirtebilir ve enterPictureInPictureMode(android.app.PictureInPictureParams) veya setPictureInPictureParams(android.app.PictureInPictureParams) kullanarak PiP moduna girdiğinizde parametreleri iletebilirsiniz. Dikkatli olun. getMaxNumPictureInPictureActions()'den fazla eklemeye çalışırsanız yalnızca maksimum sayıda ekleme yapabilirsiniz.

PiP modunda video oynatmayı sürdürme

Etkinliğiniz PiP'ye geçtiğinde sistem, etkinliği duraklatılmış duruma getirir ve etkinliğin onPause() yöntemini çağırır. Etkinlik, PiP moduna geçiş sırasında duraklatılırsa video oynatma duraklatılmamalı ve oynatılmaya devam etmelidir.

Android 7.0 (API düzeyi 24) ve sonraki sürümlerde, sistem etkinliğinizin onStop() ve onStart() yöntemlerini çağırdığında video oynatmayı duraklatıp devam ettirmeniz gerekir. Bunu yaparak uygulamanızın onPause() içinde PiP modunda olup olmadığını kontrol etme ve oynatmayı açıkça devam ettirme zorunluluğundan kurtulabilirsiniz.

setAutoEnterEnabled işaretini true olarak ayarlamadıysanız ve onPause() uygulamanızda oynatmayı duraklatmanız gerekiyorsa isInPictureInPictureMode() yöntemini çağırarak PiP modunu kontrol edin ve oynatmayı uygun şekilde yönetin. Örneğin:

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.
    }
}

Etkinliğiniz PiP modundan tam ekran moduna geri döndüğünde sistem etkinliğinizi devam ettirir ve onResume() yönteminizi çağırır.

PiP için tek bir oynatma etkinliği kullanma

Uygulamanızda, video oynatma etkinliği PiP modundayken kullanıcı ana ekranda içeriklere göz atarken yeni bir video seçebilir. Yeni videoyu, kullanıcıların kafasını karıştırabilecek yeni bir etkinlik başlatmak yerine mevcut oynatma etkinliğinde tam ekran modunda oynatın.

Video oynatma istekleri için tek bir etkinliğin kullanıldığından ve gerektiğinde PiP moduna geçildiğinden veya bu moddan çıkıldığından emin olmak için manifest dosyanızda etkinliğin android:launchMode değerini singleTask olarak ayarlayın:

<activity android:name="VideoActivity"
    ...
    android:supportsPictureInPicture="true"
    android:launchMode="singleTask"
    ...

Etkinliğinizde onNewIntent() yöntemini geçersiz kılın ve yeni videoyu işleyin. Gerekirse mevcut video oynatmayı durdurun.

Kamera uygulamaları için PiP desteği

Kamera uygulamaları için PiP'yi etkinleştirmek istiyorsanız onPause() çağrıldığında kamerayı kapatmayarak kameranın PiP modunda etkin kalmasını sağlamanız gerekir:

override fun onPause() {
    super.onPause()
    // Don't close the camera if the app is entering PiP mode
    if (!isInPictureInPictureMode) {
        closeCamera()
    }
}

Diğer kullanım alanlarında olduğu gibi, gerekli olmayan kullanıcı arayüzü öğelerini (ör. kontroller ve yer paylaşımları) gizleyin ve kamerayı kontrol etmek için özel işlemler (ör. kaydı durdurma veya kamerayı çevirme) ekleyin.

Sorunsuz geçişler için sourceRectHint'i hesaplama

Kamera vizörünün tam ekran koordinatlarını içeren doğru bir sourceRectHint sağlamak, sorunsuz bir giriş animasyonu için çok önemlidir. Sınırları, önizleme görünümünden getGlobalVisibleRect() kullanarak aşağıdaki gibi alabilirsiniz:

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)

Göz önünde bulundurulacak diğer noktalar

PiP, RAM'i düşük olan cihazlarda devre dışı bırakılmış olabilir. Uygulamanız PiP'yi kullanmadan önce hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE) yöntemini çağırarak bu özelliğin kullanılabilir durumda olup olmadığını kontrol edin.

PiP, tam ekran video oynatan etkinlikler için tasarlanmıştır. Etkinliğinizi PiP moduna geçirirken video içeriği dışında bir şey göstermeyin. Etkinliğinizin PiP moduna ne zaman girdiğini takip edin ve PiP sırasında kullanıcı arayüzünü yönetme bölümünde açıklandığı gibi kullanıcı arayüzü öğelerini gizleyin.

Bir etkinlik PiP modundayken varsayılan olarak giriş odağı almaz. PiP modundayken giriş etkinliklerini almak için MediaSession.setCallback() kullanın. setCallback() kullanımı hakkında daha fazla bilgi için Ne Çalıyor? kartını görüntüleme başlıklı makaleyi inceleyin.

Uygulamanız PiP modundayken PiP penceresinde video oynatılması, müzik çalar uygulaması veya sesli arama uygulaması gibi başka bir uygulamayla ses karışmasına neden olabilir. Bunu önlemek için videoyu oynatmaya başladığınızda ses odağı isteyin ve Ses Odağını Yönetme bölümünde açıklandığı gibi ses odağı değişikliği bildirimlerini işleyin. PiP modundayken ses odağının kaybolduğuna dair bildirim alırsanız video oynatmayı duraklatın veya durdurun.

Uygulamanız PiP moduna girmek üzereyken yalnızca en üstteki etkinliğin pencere içinde pencere moduna girdiğini unutmayın. Çok pencereli cihazlar gibi bazı durumlarda, temel etkinliğin gösterilmesi ve PiP etkinliğiyle birlikte tekrar görünür hale gelmesi mümkündür. Temel etkinliğin onResume() veya onPause() geri çağırma alması dahil olmak üzere bu durumu uygun şekilde ele almanız gerekir. Kullanıcının etkinlikle etkileşim kurması da mümkündür. Örneğin, bir video listesi etkinliğiniz ve PiP modunda oynatılan video etkinliğiniz varsa kullanıcı listeden yeni bir video seçebilir ve PiP etkinliği buna göre güncellenmelidir.

Ek örnek kod

Kotlin'de yazılmış örnek bir uygulamayı indirmek için Android PictureInPicture Sample (Kotlin) sayfasına bakın.