Dodawanie filmów przy użyciu obrazu w obrazie (PIP)

Począwszy od Androida 8.0 (poziom interfejsu API 26), Android umożliwia uruchamianie działań tryb obrazu w obrazie (PIP). Obraz w obrazie to specjalny typ trybu wielu okien, używany do odtwarzania filmów. Pozwala użytkownikowi obejrzeć film w przypiętym małym oknie w rogu ekranu podczas przechodzenia między aplikacjami lub przeglądania treści na ekranie głównym.

Obraz w obrazie wykorzystuje interfejsy API trybu wielu okien dostępne na Androidzie 7.0, przypiętego okna nakładki wideo. Aby dodać obraz w obrazie do aplikacji, musisz zarejestrować aktywności obsługujących obraz w obrazie (PIP), w razie potrzeby przełączaj aktywność na tryb obraz w obrazie; Upewnij się, że elementy interfejsu są ukryte, a film jest nadal odtwarzany, gdy jest w trybie PIP.

Okno obrazu w obrazie pojawia się w najwyższej warstwie ekranu, w rogu wybranym przez w systemie.

Obraz w obrazie jest też obsługiwany na zgodnych urządzeniach z systemem operacyjnym Android TV Android 14 (poziom interfejsu API 34) lub nowszy. Istnieje wiele podobieństw, ale warto wziąć pod uwagę dodatkowe kwestie, PIP na telewizorze

Jak użytkownicy mogą korzystać z okna obrazu w obrazie

Użytkownicy mogą przeciągnąć okno PIP w inne miejsce. Użytkownicy Androida od wersji 12 mogą też:

  • Kliknij raz okno, aby wyświetlić przełącznik trybu pełnoekranowego, przycisk zamykania, przycisk ustawień i działania niestandardowe udostępniane przez aplikację (np. odtworzenie ).

  • Dotknij dwukrotnie okna, aby przełączyć się między bieżącym a maksymalnym rozmiarem obrazu w obrazie lub minimalny rozmiar obrazu w obrazie, np. dwukrotne kliknięcie zmaksymalizowanego okna. który go minimalizuje i jednocześnie działa odwrotność.

  • Ukryj okno, przeciągając je do lewej lub prawej krawędzi. Aby przywrócić kliknij widoczną część schowka lub przeciągnij je poza nie.

  • Powiększ lub ściągnij palce, aby zmienić rozmiar okna funkcji obraz w obrazie.

Aplikacja określa, kiedy bieżąca aktywność przechodzi w tryb obrazu w obrazie. Oto kilka Przykłady:

  • Aktywność może przejść w tryb obrazu w obrazie, gdy użytkownik naciśnie przycisk ekranu głównego lub przesunie palcem na ekranie głównym do domu. W ten sposób Mapy Google nadal wyświetlają wskazówki dojazdu, gdy użytkownik wykonuje w tym samym czasie inną aktywność.

  • Aplikacja może przenieść film do trybu obraz w obrazie, gdy użytkownik wróci z powrotem go, aby przeglądać inne treści.

  • Aplikacja może przełączać film w tryb obrazu w obrazie, gdy użytkownik ogląda do końca danego odcinka serialu. Ekran główny wyświetla promocję lub podsumowanie. informacji na temat następnego odcinka serialu.

  • Twoja aplikacja może umożliwiać użytkownikom dodawanie do kolejki dodatkowych treści, oglądają film. Film jest nadal odtwarzany w trybie obraz w obrazie podczas głównego na ekranie wyświetla się aktywność dotycząca wyboru treści.

Zadeklaruj obsługę obrazu w obrazie

Domyślnie system nie obsługuje automatycznie funkcji PIP w aplikacjach. Jeśli chcesz obsługuje funkcję PIP w aplikacji, zarejestruj aktywność związaną z filmami w pliku manifestu przez ustawiam wartość true w polu android:supportsPictureInPicture. Określ też, że aktywność obsługuje zmiany w konfiguracji układu, dzięki czemu aktywność jest uruchamiany ponownie po zmianie układu w trakcie przechodzenia w trybie obrazu w obrazie.

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

Przełącz aktywność na obraz w obrazie

Począwszy od Androida 12, można przełączyć aktywność w tryb obraz w obrazie za pomocą: flagę setAutoEnterEnabled do true. Przy tym ustawieniu aktywność w razie potrzeby automatycznie przełącza się na tryb PIP bez konieczności jawnego wywoływania enterPictureInPictureMode() w onUserLeaveHint. Ten element dodatkowo płynniejsze przejścia. Szczegółowe informacje znajdziesz w artykule Tworzenie przejście z nawigacji przy użyciu gestów do trybu PIP będzie płynniejsze.

Jeśli kierujesz aplikację na Androida 11 lub starszego, aktywność musi wywołać enterPictureInPictureMode() aby przejść do trybu obraz w obrazie. Na przykład ten kod przełącza aktywność na Tryb obrazu w obrazie, gdy użytkownik kliknie specjalny przycisk w interfejsie aplikacji:

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

Możesz dodać funkcje logiczne, które przełączają aktywność w tryb PIP. znajduje się w tle. Na przykład Mapy Google przełączają się na tryb obrazu w obrazie, jeśli użytkownik naciska przycisk ekranu głównego lub przycisk Ostatnie podczas korzystania z aplikacji. Dostępne opcje wykrywaj ten przypadek, zastępując onUserLeaveHint():

Kotlin

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

Java

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

Zalecane: zapewnij użytkownikom dopracowane przejście w trybie PIP

W Androidzie 12 wprowadzono istotne ulepszenia kosmetyczne w animowanych przejściach. między pełnym ekranem a oknami PIP. Zdecydowanie zalecamy wdrożenie wszystkich obowiązujące zmiany; zmiany te są automatycznie skalowane na dużych ekranach, takich jak urządzenia składane i tablety, bez żadnych dodatkowych działań.

Jeśli Twoja aplikacja nie zawiera odpowiednich aktualizacji, przejścia w obrazie obrazu będą nadal wykonywane działa, ale animacje są mniej dopracowane. Na przykład przejście z pełnego ekranu do trybu PIP może spowodować, że okno zanim pojawi się ponownie po zakończeniu przejścia.

Obejmują one następujące elementy.

  • Płynniejsze przejście z nawigacji przy użyciu gestów do trybu obraz w obrazie
  • Ustawiam właściwą wartość sourceRectHint umożliwiającą włączanie i wyłączanie trybu obraz w obrazie
  • Wyłączanie płynnej zmiany rozmiaru w przypadku treści innych niż wideo

Patrz: Android Próbka obrazu w obrazie Kotlin jako materiał referencyjny umożliwiający dopracowanie przejścia.

Płynniejsze przejście do trybu PIP z nawigacji przy użyciu gestów

Począwszy od Androida 12 flaga setAutoEnterEnabled zapewnia wiele płynniejsza animacja przy przechodzeniu do treści wideo w trybie obraz w obrazie za pomocą gestu nawigacji, np. podczas przesuwania w górę strony głównej z pełnego ekranu.

Wykonaj poniższe czynności, aby wprowadzić tę zmianę. Zapoznaj się z tym przykładem, aby uzyskać odniesienie:

  1. Używaj setAutoEnterEnabled do tworzenia PictureInPictureParams.Builder:

    Kotlin

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

    Java

    setPictureInPictureParams(new PictureInPictureParams.Builder()
        .setAspectRatio(aspectRatio)
        .setSourceRectHint(sourceRectHint)
        .setAutoEnterEnabled(true)
        .build());
    
  2. Zadzwoń pod numer setPictureInPictureParams i podaj aktualne informacje PictureInPictureParams przed czasem. Aplikacja nie czeka na onUserLeaveHint – wywołanie zwrotne (tak jak w Androidzie 11).

    Możesz np. zadzwonić do: setPictureInPictureParams pierwsze odtworzenie, a kolejne odtworzenie, jeśli format obrazu zostanie zmieniony.

  3. Zadzwoń pod numer setAutoEnterEnabled(false), ale tylko wtedy, gdy jest to konieczne. Przykład: To dobry pomysł, by włączyć obraz w obrazie, jeśli bieżący film jest wstrzymany. stanu.

Ustaw odpowiednią wartość sourceRectHint umożliwiającą włączanie i wyłączanie trybu PIP

Od wprowadzenia PIP w Androidzie 8.0: setSourceRectHint wskazać obszar aktywności, który jest widoczny po przejściu na obraz w obrazie – np. granice wyświetlenia filmu w odtwarzaczu.

W Androidzie 12 system używa funkcji sourceRectHint, aby zapewnić znacznie płynniejsze działanie ani na animację.

Aby prawidłowo ustawić sourceRectHint na potrzeby włączania i wyłączania trybu obraz w obrazie:

  1. Utwórz PictureInPictureParams z użyciem prawidłowych granic, takich jak sourceRectHint. Zalecamy również załączenie detektor zmiany układu w odtwarzaczu:

    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. W razie potrzeby zaktualizuj sourceRectHint, zanim system rozpocznie przejścia. Gdy system niedługo wyjdzie z trybu obraz w obrazie, aktywność hierarchia widoków jest ułożona zgodnie z konfiguracją miejsca docelowego (na przykład pełny ekran). Aplikacja może dołączyć detektor zmian układu do widoku głównego lub obejrzenie reklamy (np. obejrzenie odtwarzacza wideo), aby wykryć zdarzenie oraz zaktualizuj element sourceRectHint przed rozpoczęciem animacji.

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

Wyłącz płynną zmianę rozmiaru w przypadku treści innych niż wideo

Android 12 dodaje flagę setSeamlessResizeEnabled, która zapewnia płynniejsza animacja przenikania przy zmianie rozmiaru treści innych niż wideo w obrazie w obrazie okno. Wcześniej zmiana rozmiaru treści innych niż wideo w oknie PIP mogła spowodować zaciemnianie elementów wizualnych.

Aby wyłączyć płynną zmianę rozmiaru w przypadku treści innych niż wideo:

Kotlin

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

Java

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

Obsługa interfejsu podczas obrazu w obrazie

Po uruchomieniu lub zamknięciu trybu obraz w obrazie system wywołuje Activity.onPictureInPictureModeChanged() lub Fragment.onPictureInPictureModeChanged()

Te wywołania zwrotne należy zastąpić, aby ponownie wykorzystać elementy interfejsu aktywności. Google Keep pamiętaj, że w trybie PIP Twoja aktywność jest wyświetlana w małym oknie. Użytkownicy nie mogą interakcji z elementami interfejsu aplikacji, gdy jest ona w trybie Obraz w obrazie, oraz małe elementy interfejsu mogą być niewidoczne. Odtwarzanie filmów z minimalistyczny interfejs użytkownika zapewnia użytkownikom najlepsze wrażenia.

Jeśli aplikacja musi udostępniać niestandardowe działania dla obrazu w obrazie, zapoznaj się z sekcją Dodawanie na tej stronie. Usuń inne elementy interfejsu przed aktywność przechodzi w obraz w obrazie i jest przywracana po włączeniu trybu pełnoekranowego ponownie:

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

Dodaj elementy sterujące

Okno obrazu w obrazie może zawierać elementy sterujące, gdy użytkownik otworzy menu okna (przez dotykając okna na komórce lub wybierając menu z telewizora zdalnie).

Jeśli aplikacja ma aktywne multimedia sesja, a następnie odtwarzanie, pojawią się elementy sterujące, by wstrzymać, dalej i wstecz.

Możesz również bezpośrednio określić działania niestandardowe, tworząc PictureInPictureParams z PictureInPictureParams.Builder.setActions() przed przejściem w tryb obrazu w obrazie oraz przekazać parametry po przejściu w tryb enterPictureInPictureMode(android.app.PictureInPictureParams) lub setPictureInPictureParams(android.app.PictureInPictureParams). Zachowaj ostrożność. Jeśli spróbujesz dodać więcej niż getMaxNumPictureInPictureActions() otrzymasz tylko maksymalną liczbę.

Kontynuuję odtwarzanie filmu w trybie obraz w obrazie

Gdy aktywność przełączy się na obraz w obrazie, system umieszcza ją w i wywołuje metodę onPause(). Wideo odtwarzanie nie powinno być wstrzymywane. Zamiast tego można je kontynuować, jeśli aktywność jest wstrzymano podczas przechodzenia w tryb obrazu w obrazie.

W Androidzie 7.0 i nowszych należy wstrzymywać i wznawiać odtwarzanie filmu, gdy system wywołuje metodę onStop() i onStart() W ten sposób można uniknąć sprawdzania, czy aplikacja działa w trybie PIP w trybie onPause() oraz konkretne kontynuowanie odtwarzania.

Jeśli flaga setAutoEnterEnabled nie jest ustawiona na true i musisz: wstrzymaj odtwarzanie w swojej implementacji onPause(), sprawdź tryb obrazu w obrazie, wywołując isInPictureInPictureMode() i odpowiednio obsługuj odtwarzanie. Na przykład:

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

Gdy aktywność przełączy się z powrotem na tryb pełnoekranowy, system wznowi aktywność i zadzwoni na onResume().

Używaj pojedynczej aktywności związanej z odtwarzaniem na potrzeby funkcji PIP

Użytkownik może wybrać nowy film podczas przeglądania treści w aplikacji. ekran główny, podczas gdy odtwarzana jest aktywność wideo w trybie PIP. Odtwórz nowy film w istniejącej aktywności związanej z odtwarzaniem w trybie pełnoekranowym, zamiast uruchamiać nowe działanie, które może zdezorientować użytkownika.

Aby mieć pewność, że pojedyncza aktywność będzie używana do żądań odtwarzania filmów i przełączana włącz lub wyłącz tryb PIP odpowiednio do potrzeb, ustaw android:launchMode aktywności na singleTask w pliku manifestu:

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

W aktywności zastąp onNewIntent() i włączyć odtwarzanie nowego filmu, w razie potrzeby zatrzymując odtwarzanie istniejącego.

Sprawdzone metody

Obraz w obrazie może być wyłączony na urządzeniach z małą ilością pamięci RAM. Zanim aplikacja zacznie korzystać z PIP: aby sprawdzić dostępność usługi, zadzwoń pod numer hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)

Obraz w obrazie jest przeznaczony do działań, w których odtwarzane są filmy na pełnym ekranie. Podczas zmiany w trybie PIP, unikaj wyświetlania niczego oprócz treści wideo. Śledź, gdy aktywność przechodzi w tryb PIP i ukrywa elementy interfejsu zgodnie z opisem w sekcji Obsługa interfejsu użytkownika podczas obrazu w obrazie.

Gdy aktywność jest w trybie obrazu w obrazie, domyślnie nie jest ona zaznaczona. Do odbieraj zdarzenia wejściowe w trybie obraz w obrazie, użyj MediaSession.setCallback() Więcej informacji o używaniu funkcji setCallback() znajdziesz w sekcji Wyświetlanie funkcji Co jest grane .

Gdy aplikacja jest w trybie PIP, odtwarzanie filmu w jej oknie może powodować odtwarzanie dźwięku zakłócenia działania innej aplikacji, np. odtwarzacza muzyki lub aplikacji do wyszukiwania głosowego. Aby tego uniknąć, poproś o uaktywnienie dźwięku po rozpoczęciu odtwarzania filmu i ustaw powiadomienia o zmianie skupienia dźwięku, zgodnie z opisem w sekcji Zarządzanie dźwiękiem Ostrość. Jeśli otrzymasz powiadomienie utraty ostrości dźwięku w trybie obrazu w obrazie, wstrzymać lub zatrzymać odtwarzanie filmu.

Pamiętaj, że gdy aplikacja ma przejść do trybu obrazu w obrazie, uwzględniana jest tylko najlepsza aktywność. obraz w obrazie. W niektórych sytuacjach, na przykład na urządzeniach z trybem wielu okien, możliwe, że poniższa aktywność będzie teraz wyświetlana i ponownie widoczna obok: działania funkcji obraz w obrazie. Należy odpowiednio zająć się tą sprawą, łącznie z aktywność poniżej, czyli otrzymanie wywołania zwrotnego onResume() lub onPause(). Jest także jest możliwe, że użytkownik będzie mógł wejść w interakcję z aktywnością. Jeśli na przykład masz aktywność związaną z listą filmów oraz aktywność związaną z odtwarzaniem filmów w trybie obrazu w pionie, użytkownik może wybrać nowy film z listy, co spowoduje zaktualizowanie aktywności obrazu w obrazie odpowiednio się zmienia.

Dodatkowy przykładowy kod

Aby pobrać przykładową aplikację napisaną w języku Kotlin, zobacz Android PictureInPicture Sample. (Kotlin).