Pencere içinde pencere (PiP) özelliğini kullanarak video ekleme

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

Android, Android 8.0 (API düzeyi 26) sürümünden itibaren etkinliklerin pencere içinde pencere (PiP) modunda başlatılmasına olanak tanır. PiP, çoğunlukla video oynatma için kullanılan özel bir çoklu pencere modu türüdür. Kullanıcıların uygulamalar arasında geçiş yaparken veya ana ekrandaki içeriklere göz atarken ekranın bir köşesine sabitlenmiş küçük bir pencerede video izlemesine olanak tanır.

PiP, sabitlenmiş video yer paylaşımı penceresini sağlamak için Android 7.0'da kullanıma 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. İkisi arasında birçok benzerlik olsa da TV'de PiP'yi kullanırken dikkate alınması gereken başka noktalar da vardır.

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

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

  • Tam ekran açma/kapatma düğmesi, kapat düğmesi, ayarlar düğmesi ve uygulamanız tarafından sağlanan özel işlemleri (ör. oynatma kontrolleri) görüntülemek için pencereye tek dokunun.

  • Mevcut PiP boyutu ile maksimum veya minimum PiP boyutu arasında geçiş yapmak için pencereye iki kez dokunun. Örneğin, ekranı kaplayan bir pencereye iki kez dokunduğunuzda pencere en aza iner, tam tersi de geçerlidir.

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

  • İki parmağınızı yakınlaştırmak veya uzaklaştırmak için kullanarak PiP penceresini yeniden boyutlandırın.

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

  • Kullanıcı ana sayfa düğmesine dokunduğunda veya ekranı yukarı kaydırarak ana sayfaya dokunduğunda bir etkinlik PiP moduna girebilir. Google Haritalar, kullanıcı aynı anda başka bir etkinlik gerçekleştirirken yol tariflerini göstermeye bu şekilde devam eder.

  • Kullanıcı videodan geri dönüp diğer içeriklere göz atarken uygulamanız videoyu PiP moduna geçirebilir.

  • Uygulamanız, kullanıcı bir içeriğin 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 eklemelerine olanak tanıyabilir. Ana ekranda içerik seçimi etkinliği gösterilirken video PiP modunda oynatılmaya devam eder.

PiP desteğini bildirme

Sistem, varsayılan olarak uygulamalar için PiP'yi otomatik olarak desteklemez. Uygulamanızda PIP'yi desteklemek istiyorsanız android:supportsPictureInPicture öğesini true olarak ayarlayarak video etkinliğinizi manifest dosyanıza kaydedin. Ayrıca, PiP modu geçişlerinde düzen değişiklikleri olduğunda 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"
    ...

Etkinliğinizi PIP'e geçirme

Android 12'den itibaren setAutoEnterEnabled işaretini true olarak ayarlayarak etkinliğinizi PiP moduna geçirebilirsiniz. Bu ayar etkinleştirildiğinde bir etkinlik, onUserLeaveHint içinde açıkça enterPictureInPictureMode() çağrısı yapmak zorunda kalmadan gerektiğinde otomatik olarak PiP moduna geçer. Bu, çok daha sorunsuz geçişler sağlamanın ek avantajını da sunar. Ayrıntılar için Hareketle gezinme sırasında 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() çağrısı yapması gerekir. Örneğin, aşağıdaki kod, kullanıcı uygulamanın kullanıcı arayüzünde özel bir düğmeyi tıkladığında etkinliği PiP moduna geçirir:

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

Bir etkinliği arka plana taşımak yerine PiP moduna geçiren mantık ekleyebilirsiniz. Örneğin, Google Haritalar uygulamada gezinme sırasında kullanıcı ana sayfa veya son aramalar düğmesine basarsa PIP moduna geçer. onUserLeaveHint() değerini geçersiz kılarak bu durumu yakalayabilirsiniz:

Kotlin

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

Java

@Override
public void onUserLeaveHint () {
    if (iWantToBeInPipModeNow()) {
        enterPictureInPictureMode();
    }
}

Önerilen: Kullanıcılara kusursuz bir PiP geçiş deneyimi sunun

Android 12'de tam ekran ile PiP pencereleri arasındaki animasyonlu geçişlere önemli görünüm geliştirmeler eklendi. Geçerli tüm değişiklikleri uygulamanızı önemle tavsiye ederiz. Bu değişiklikleri yaptıktan sonra, başka bir işlem yapmanıza gerek kalmadan katlanabilir cihazlar ve tabletler gibi büyük ekranlara otomatik olarak ölçeklendirilir.

Uygulamanız geçerli güncellemeleri içermiyorsa PIP geçişleri çalışmaya devam eder ancak animasyonlar daha az cilalıdır. Örneğin, tam ekrandan PiP moduna geçiş, geçiş sırasında PiP penceresinin geçiş tamamlandığında yeniden görünmeden önce kaybolmasına neden olabilir.

Bu değişiklikler aşağıdakileri kapsar.

  • Hareketle gezinme modundan PIP moduna geçişi daha sorunsuz hale getirme
  • PiP moduna girmek ve moddan çı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 sunmak için Android Kotlin PictureInPicture örneğine göz atın.

Hareketle gezinme modundan PIP moduna geçişleri daha sorunsuz hale getirme

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

Bu değişikliği yapmak için aşağıdaki adımları uygulayın ve referans olarak bu örneği inceleyin:

  1. PictureInPictureParams.Builder URL'sini oluşturmak için setAutoEnterEnabled kullanın:

    Kotlin

    setPictureInPictureParams(PictureInPictureParams.Builder()
        .setAspectRatio(aspectRatio)
        .setSourceRectHint(sourceRectHint)
        .setAutoEnterEnabled(true)
        .build())

    Java

    setPictureInPictureParams(new PictureInPictureParams.Builder()
        .setAspectRatio(aspectRatio)
        .setSourceRectHint(sourceRectHint)
        .setAutoEnterEnabled(true)
        .build());
  2. Güncel PictureInPictureParams ile setPictureInPictureParams'ü erkenden arayın. Uygulama, onUserLeaveHint geri çağırma işlevini beklemez (Android 11'de beklediği gibi).

    Örneğin, en boy oranı değiştirilirse ilk oynatma işleminde ve sonraki oynatma işlemlerinde setPictureInPictureParams işlevini çağırabilirsiniz.

  3. setAutoEnterEnabled(false)'ü yalnızca gerektiğinde arayın. Örneğin, mevcut oynatma duraklatılmış durumdaysa büyük olasılıkla PiP moduna girmek istemezsiniz.

PiP moduna girmek ve moddan çıkmak için uygun bir sourceRectHint ayarlayın

Android 8.0'da PiP'nin kullanıma sunulmasından itibaren setSourceRectHint, etkinliğin pencere içinde pencere moduna geçişten sonra görünen alanını (ör. bir video oynatıcıdaki video görüntüleme sınırları) belirtiyordu.

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

PiP moduna girmek ve moddan çıkmak için sourceRectHint'ü doğru şekilde ayarlamak üzere:

  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:

    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);
  2. Gerekirse sistem çıkış geçişini başlatmadan önce sourceRectHint öğesini güncelleyin. Sistem PiP modundan çıkmak üzereyken etkinliğin görüntü hiyerarşisi hedef yapılandırmasına (ör. tam ekran) göre düzenlenir. Uygulama, etkinliği algılamak 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 işleyici ekleyebilir ve animasyon başlamadan önce sourceRectHint öğesini güncelleyebilir.

    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());
        }
    });

Video olmayan içerik için sorunsuz yeniden boyutlandırmayı devre dışı bırak

Android 12'de, PiP penceresindeki video dışı içerikler yeniden boyutlandırıldığında çok daha yumuşak bir geçiş animasyonu sağlayan setSeamlessResizeEnabled işareti eklendi. Daha önce, PiP penceresindeki video dışı içeriğin boyutunu değiştirmek rahatsız edici görsel kusurlara neden olabiliyordu.

Video olmayan içeriklerde sorunsuz yeniden boyutlandırmayı devre dışı bırakmak için:

Kotlin

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

Java

setPictureInPictureParams(new PictureInPictureParams.Builder()
    .setSeamlessResizeEnabled(false)
    .build());

PiP sırasında kullanıcı arayüzünü işleme

Etkinlik, Pencere İçinde Pencere (PiP) moduna girdiğinde veya bu moddan çıktığında sistem Activity.onPictureInPictureModeChanged() veya Fragment.onPictureInPictureModeChanged() çağrısı yapar.

Android 15'te, PiP moduna girerken daha da sorunsuz bir geçiş sağlayan değişiklikler sunuluyor. Bu, PiP'e giren ana kullanıcı arayüzünün üzerine yerleştirilmiş kullanıcı arayüzü öğeleri olan uygulamalar için faydalıdır.

Geliştiriciler, üste binen kullanıcı arayüzü öğelerinin görünürlüğünü değiştiren mantığı tanımlamak için onPictureInPictureModeChanged() geri çağırma işlevini kullanır. Bu geri çağırma işlevi, PiP'ye girme veya çıkma animasyonu tamamlandığında tetiklenir. Android 15'ten itibaren PictureInPictureUiState sınıfı yeni bir durum içeriyor.

Bu yeni kullanıcı arayüzü durumunda, 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özlemler. PiP modundayken uygulamayla alakalı olmayan birçok kullanıcı arayüzü öğesi vardır. Örneğin, öneriler, yaklaşan video, derecelendirmeler ve başlıklar gibi bilgileri içeren görünümler veya düzenler. Uygulama PiP moduna girdiğinde bu kullanıcı arayüzü öğelerini gizlemek için onPictureInPictureUiStateChanged() geri arama işlevini kullanın. Uygulama, PiP penceresinden tam ekran moduna geçtiğinde aşağıdaki örneklerde gösterildiği gibi bu öğeleri göstermek için onPictureInPictureModeChanged() geri çağırma işlevini kullanın:

Kotlin

override fun onPictureInPictureUiStateChanged(pipState: PictureInPictureUiState) {
        if (pipState.isTransitioningToPip()) {
          // Hide UI elements.
        }
    }

Java

@Override
public void onPictureInPictureUiStateChanged(PictureInPictureUiState pipState) {
        if (pipState.isTransitioningToPip()) {
          // Hide UI elements.
        }
    }

Kotlin

override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean) {
        if (isInPictureInPictureMode) {
          // Unhide UI elements.
        }
    }

Java

@Override
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
        if (isInPictureInPictureMode) {
          // Unhide UI elements.
        }
    }

Alakasız kullanıcı arayüzü öğelerinin (PiP penceresi için) bu hızlı görünürlük açma/kapatma özelliği, PiP giriş animasyonunun daha akıcı ve titreşimsiz olmasını sağlar.

Etkinliğin kullanıcı arayüzü öğelerini yeniden çizmek için bu geri çağırma işlevlerini 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. En iyi kullanıcı deneyimini, minimal kullanıcı arayüzüne sahip video oynatma etkinlikleri sağlar.

Uygulamanızın PiP için özel işlemler sağlaması gerekiyorsa bu sayfadaki Denetimler ekleme bölümüne bakın. Etkinliğiniz PiP'ye girmeden önce diğer kullanıcı arayüzü öğelerini kaldırın ve etkinliğiniz tekrar tam ekran haline geldiğinde bu öğeleri 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 kontroller gösterilir.

PIP moduna girmeden önce PictureInPictureParams.Builder.setActions() ile PictureInPictureParams oluşturarak ve enterPictureInPictureMode(android.app.PictureInPictureParams) veya setPictureInPictureParams(android.app.PictureInPictureParams) kullanarak PIP moduna girdiğinizde parametreleri ileterek özel işlemleri açıkça belirtebilirsiniz. Dikkatli olun. getMaxNumPictureInPictureActions() değerinden daha fazla ekleme yapmaya çalışırsanız yalnızca maksimum sayıyı alırsınız.

PiP modundayken video oynatmaya devam etme

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

Android 7.0 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()'te PiP modunda olup olmadığını kontrol etmek ve oynatmaya açıkça devam etmek zorunda kalmazsınız.

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

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

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, bir video oynatma etkinliği PiP modundayken kullanıcı ana ekranda içeriklere göz atarken yeni bir video seçebilir. Kullanıcının kafasını karıştırabilecek yeni bir etkinlik başlatmak yerine, yeni videoyu mevcut oynatma etkinliğinde tam ekran modunda oynatın.

Video oynatma istekleri için tek bir etkinliğin kullanılmasını ve gerektiğinde PiP moduna girip çıkmasını sağlamak üzere 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() değerini geçersiz kılın ve gerekirse mevcut video oynatmayı durdurarak yeni videoyu işleyin.

En iyi uygulamalar

PiP, RAM'i düşük olan cihazlarda devre dışı bırakılabilir. Uygulamanız PiP'yi kullanmadan önce hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE) çağrısını yaparak bu özelliğin kullanılabilir 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 izleyin 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ğına alınmaz. PIP modundayken giriş etkinlikleri almak için MediaSession.setCallback() simgesini kullanın. setCallback() simgesini kullanma hakkında daha fazla bilgi için Ne çalıyor kartı görüntüleme başlıklı makaleyi inceleyin.

Uygulamanız PiP modundayken PiP penceresindeki video oynatımı, müzik çalar veya sesli arama uygulaması gibi başka bir uygulamada ses parazitine neden olabilir. Bunu önlemek için videoyu oynatmaya başladığınızda ses odağını 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'ye girmek üzereyken yalnızca en üstteki etkinliğin PiP'ye girdiğini unutmayın. Çok pencereli cihazlar gibi bazı durumlarda, PiP etkinliğinin yanında aşağıdaki etkinliğin gösterilmesi ve tekrar görünür hale gelmesi mümkündür. Bu durumu uygun şekilde ele almanız gerekir. onResume() ya da onPause() geri araması almak için aşağıdaki etkinlikler de buna dahildir. Kullanıcının etkinlikle etkileşime geçmesi de mümkündür. Örneğin, PiP modunda gösterilen bir video listesi etkinliğiniz ve video oynatma etkinliğiniz varsa kullanıcı listeden yeni bir video seçebilir. PiP etkinliği buna göre güncellenir.

Ek örnek kod

Kotlin ile yazılmış örnek bir uygulama indirmek için Android PictureInPicture Örneği (Kotlin) başlıklı makaleyi inceleyin.