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

Android 8.0 (API düzeyi 26) sürümünden başlayarak, etkinliklerin pencere içinde pencere (PIP) modunda başlatılabilmesini sağlar. PiP, çoğunlukla video oynatma için kullanılan özel bir çoklu pencere modu türüdür. Kullanıcının uygulamalar arasında gezinirken veya ana ekranda içeriklere göz atarken ekranın bir köşesine sabitlenmiş küçük bir pencerede video izlemesini sağlar.

PiP, sabitlenmiş video yer paylaşımı penceresi sağlamak için Android 7.0'da kullanıma sunulan çoklu pencere API'lerinden yararlanır. Uygulamanıza PiP eklemek için PiP'yi destekleyen etkinliklerinizi kaydetmeniz, gerektiği şekilde etkinliğinizi PiP moduna geçirmeniz, ayrıca kullanıcı arayüzü öğelerinin gizlendiğinden ve etkinlik PiP modundayken 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.

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:

  • Tam ekran açma/kapatma düğmesi, kapatma 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 bir kez dokunun.

  • Geçerli 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 boyut küçültülür, bunun tersi de doğru olur.

  • Pencereyi sol veya sağ kenara sürükleyerek saklayın. Pencerenin kilidini açmak için saklanmış pencerenin görünür bölümüne dokunun veya dışarı sürükleyin.

  • Yakınlaştırmak için sıkıştırarak PiP penceresini yeniden boyutlandırın.

Uygulamanız, geçerli etkinliğin PiP moduna gireceği zamanı kontrol eder. Bazı örnekler:

  • Bir etkinlik, kullanıcı ana sayfa düğmesine dokunduğunda veya ana ekrana doğru hızlıca kaydırdığında PiP moduna girebilir. Kullanıcı aynı anda başka bir etkinlik çalıştırırken Google Haritalar yol tariflerini görüntülemeye bu şekilde devam eder.

  • Kullanıcı diğer içeriklere göz atmak için videodan geri döndüğünde uygulamanız bir videoyu PiP moduna taşıyabilir.

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

  • Uygulamanız, kullanıcıların video izlerken ek içerikleri sıraya almaları için bir yol sağlayabilir. Ana ekranda bir içerik seçimi etkinliği gösterilirken video PiP modunda oynatılmaya devam ediyor.

PiP desteği bildirme

Varsayılan olarak sistem, uygulamalar için PiP'yi otomatik olarak desteklemez. Uygulamanızda PiP desteğinin bulunmasını 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şikliği olduğunda etkinliğinizin yeniden başlatılmaması için etkinliğinizin düzen yapılandırma değişikliklerini işlediğini belirtin.

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

Etkinliğinizi PiP'ye geçirin

Android 12 sürümünden itibaren setAutoEnterEnabled işaretini true olarak ayarlayarak etkinliğinizi PiP moduna geçirebilirsiniz. Bu ayar kullanıldığında, etkinlikler onUserLeaveHint içinde açıkça enterPictureInPictureMode() çağrısı yapmak zorunda kalmadan otomatik olarak PiP moduna geçer. Bu ayrıca çok daha yumuşak geçişler sağlama avantajını da sunar. Ayrıntılı bilgi 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 PiP moduna geçmek için bir etkinlik enterPictureInPictureMode() çağrısı yapmalıdır. Örneğin, aşağıdaki kod, kullanıcı uygulamanın kullanıcı arayüzündeki ö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 gitmek yerine PiP moduna geçiren bir mantık eklemek isteyebilirsiniz. Örneğin, kullanıcı uygulama gezinirken ana sayfa veya son kullanılanlar düğmesine basarsa Google Haritalar, PiP moduna geçer. Bu destek kaydını, onUserLeaveHint() etiketini geçersiz kılarak tespit edebilirsiniz:

Kotlin

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

Java

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

Öneri: Kullanıcılara şık bir PiP geçiş deneyimi sunun

Android 12, tam ekran ve PiP pencereler arasındaki animasyonlu geçişlere önemli estetik iyileştirmeler ekledi. Geçerli tüm değişiklikleri uygulamanızı kesinlikle öneririz. Uygulama tamamlandıktan sonra, bu değişiklikler başka bir işlem gerektirmeden katlanabilir cihazlar ve tabletler gibi büyük ekranlara göre otomatik olarak ölçeklenir.

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

Bu değişiklikler aşağıdakileri kapsamaktadır.

  • Hareketle gezinme sayesinde PiP moduna daha sorunsuz geçiş
  • PiP moduna girmek ve bu moddan çıkmak için uygun bir sourceRectHint ayarlama
  • Video olmayan içerik için sorunsuz yeniden boyutlandırmayı devre dışı bırakma

Kaliteli bir geçiş deneyimi sunmak için referans olarak Android Kotlin PictureInPicture örneğine bakın.

Hareketle gezinmeden PiP moduna daha sorunsuz geçiş yapın

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

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

  1. PictureInPictureParams.Builder 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. setPictureInPictureParams adlı kişiyi en güncel PictureInPictureParams bilgisiyle erkenden arayın. Uygulama, Android 11'de olduğu gibi onUserLeaveHint geri çağırma işlemini beklemez.

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

  3. Gerekli olduğunda setAutoEnterEnabled(false) numaralı telefonu arayın. Örneğin, mevcut oynatma duraklatılmış bir durumdaysa muhtemelen PiP'yi girmek istemezsiniz.

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

Android 8.0'da PiP'nin kullanıma sunulmasından itibaren setSourceRectHint, pencere içinde pencere moduna geçişin ardından görülebilecek etkinlik alanını (örneğin, bir video oynatıcıda video görüntüleme sınırları) belirtmişti.

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

PiP moduna girerken ve bu moddan çıkarken sourceRectHint ayarını doğru şekilde yapmak için:

  1. sourceRectHint şeklinde uygun sınırları kullanarak PictureInPictureParams oluşturun. Video oynatıcıya bir düzen değişikliği dinleyicisi eklemenizi de ö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ünüm hiyerarşisi hedef yapılandırmasına eklenir (örneğin, tam ekran). Uygulama, etkinliği algılamak ve animasyon başlamadan önce sourceRectHint öğesini 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.

    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 penceresinde video olmayan içerikleri yeniden boyutlandırırken çok daha akıcı bir çapraz geçiş animasyonu sağlayan setSeamlessResizeEnabled işareti eklenir. Önceden, video olmayan içeriğin PiP penceresinde yeniden boyutlandırılması rahatsız edici görsel yapılar oluşturabiliyordu.

Video olmayan içerik için kesintisiz yeniden boyutlandırmayı devre dışı bırakmak üzere:

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 PiP moduna girdiğinde veya bu moddan çıktığında sistem, Activity.onPictureInPictureModeChanged() veya Fragment.onPictureInPictureModeChanged() yöntemini çağırır.

Etkinliğin kullanıcı arayüzü öğelerini yeniden çizmek için bu geri çağırmaları geçersiz kılmanız gerekir. PiP modunda etkinliğinizin küçük bir pencerede gösterildiğini unutmayın. Uygulamanız 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üyle 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'ye girmeden önce diğer kullanıcı arayüzü öğelerini kaldırın ve etkinliğiniz tekrar tam ekran hale geldiğinde geri yükleyin:

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

Kontrol ekle

Kullanıcı pencerenin menüsünü açtığında (mobil cihazda pencereye dokunarak veya TV uzaktan kumandasından menüyü seçerek) PiP penceresinde kontroller görüntülenebilir.

Bir uygulamada etkin medya oturumu varsa oynat, duraklat, sonraki ve önceki kontroller görünür.

Ayrıca, PiP moduna girmeden önce PictureInPictureParams.Builder.setActions() ile PictureInPictureParams oluşturarak ve PiP moduna girerken parametreleri enterPictureInPictureMode(android.app.PictureInPictureParams) ya da setPictureInPictureParams(android.app.PictureInPictureParams) ile 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ı elde edersiniz.

PiP'de video oynatmaya devam ediliyor

Etkinliğiniz PiP'ye geçtiğinde sistem etkinliği duraklatılmış duruma getirir ve etkinliğin onPause() yöntemini çağırır. Video oynatma duraklatılmamalı ve etkinlik PiP modundayken duraklatılırsa oynatılmaya devam etmelidir.

Android 7.0 ve sonraki sürümlerde, sistem tarafından onStop() ve onStart() çağrıldığında video oynatmayı duraklatıp devam ettirmeniz gerekir. Bu sayede uygulamanızın onPause() işlevinde PiP modunda olup olmadığını kontrol etmek ve oynatmaya açık bir şekilde devam etmek zorunda kalmazsınız.

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 oynatma işlemini uygun şekilde gerçekleştirin. Ö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 tekrar tam ekran moduna geçtiğinde sistem etkinliğinizi devam ettirir ve onResume() yönteminizi çağırır.

PiP için tek bir oynatma etkinliği kullan

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ının kafasını karıştırabilecek yeni bir etkinlik başlatmak yerine tam ekran modunda mevcut oynatma etkinliğinde oynatın.

Video oynatma istekleri için tek bir etkinliğin kullanıldığından ve gerektiğinde PiP moduna geçirildiğinden veya çıkarı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() değerini geçersiz kılın ve yeni videoyu işleyin, gerekirse mevcut videonun oynatılmasını durdurun.

En iyi uygulamalar

RAM'i düşük olan cihazlarda PiP devre dışı bırakılabilir. Uygulamanız PiP'yi kullanmadan önce hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE) numaralı telefonu arayarak 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 hiçbir şey göstermekten kaçının. Etkinliğinizin PiP moduna girmesini izleyin ve PIP sırasında kullanıcı arayüzünü kullanma 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() değerini kullanın. setCallback() öğesinin kullanımıyla ilgili daha fazla bilgi için Ne Çalıyor? kartı görüntüleme konusuna bakın.

Uygulamanız PiP modundayken PiP penceresinde video oynatma, müzik çalar uygulaması veya sesli arama uygulaması gibi başka uygulamalarda ses parazitine neden olabilir. Bunu önlemek için, videoyu oynatmaya başladığınızda ses odağı isteyin ve Ses Odaklılığı Yönetme bölümünde açıklandığı şekilde ses odağı değişikliği bildirimlerini yönetin. PiP modundayken ses odağı kaybıyla ilgili bildirim alırsanız video oynatmayı duraklatın veya durdurun.

Uygulamanız PIP'ye girmek üzereyken yalnızca en üstteki etkinliğin pencere içinde pencere moduna girdiğine dikkat edin. Çok pencereli cihazlarda olduğu gibi bazı durumlarda aşağıdaki etkinliğin gösterilmesi ve PiP etkinliğinin yanında tekrar görünür hale gelmesi mümkündür. Bu durumu uygun şekilde ele almanız gerekir. Örneğin, bir onResume() veya onPause() geri araması almak için aşağıdaki etkinliği gerçekleştirmeniz gerekir. Kullanıcının bu etkinlikle etkileşimde bulunması da mümkündür. Örneğin, bir video listesi etkinliğiniz gösteriliyorsa ve PiP modunda video oynatma etkinliğiniz varsa kullanıcı listeden yeni bir video seçebilir ve PiP etkinliği buna göre güncellenir.

Ek örnek kod

Android'de yazılmış örnek bir uygulamayı indirmek için Pencere İçinde Pencere Örneği bölümüne bakın. Kotlin dilinde yazılmış örnek bir uygulama indirmek için Android Picture InPicture Örneği (Kotlin) sayfasına bakın.