Od Androida 8.0 (poziom API 26) aktywności mogą być uruchamiane w trybie obraz w obrazie. PiP to specjalny rodzaj trybu wielu okien, który jest najczęściej używany do odtwarzania filmów. Umożliwia użytkownikowi oglądanie filmu w małym oknie przypiętym do rogu ekranu, a jednocześnie przełączanie innych aplikacji lub wyszukiwanie treści na głównym ekranie.
Tryb obrazu w obrazie korzysta z interfejsów API obsługujących wiele okien, które są dostępne w Androidzie 7.0, aby wyświetlać przypięte okno nakładki wideo. Aby dodać do aplikacji tryb obrazu w obrazie, musisz zarejestrować działania, które go obsługują, w razie potrzeby przełączyć działanie w tryb obrazu w obrazie i upewnić się, że elementy interfejsu są ukryte, a odtwarzanie wideo jest kontynuowane, gdy działanie jest w trybie obrazu w obrazie.
Okno PiP pojawi się na wierzchniej warstwie ekranu w rogu wybranym przez system.
Tryb obrazu w obrazie jest też obsługiwany na zgodnych urządzeniach z Androidem TV OS z Androidem 14 (API na poziomie 34) lub nowszym. Chociaż istnieje wiele podobieństw, podczas korzystania z obrazu w obrazie na telewizorze należy wziąć pod uwagę dodatkowe kwestie.
Jak użytkownicy mogą wchodzić w interakcję z oknem PiP
Użytkownicy mogą przeciągnąć okno PiP w inne miejsce. Od Androida 12 użytkownicy mogą też:
- Kliknij okno, aby wyświetlić przełącznik pełnego ekranu, przycisk zamykania, przycisk ustawień i niestandardowe działania udostępniane przez aplikację (np. elementy sterujące odtwarzaniem). 
- Kliknij dwukrotnie okno, aby przełączać się między bieżącym rozmiarem obrazu w obrazie a maksymalnym lub minimalnym rozmiarem obrazu w obrazie. Na przykład kliknięcie dwukrotne zmaksymalizowanego okna spowoduje jego zminimalizowanie i odwrotnie. 
- Ukryj okno, przeciągając je do lewej lub prawej krawędzi. Aby wycofać okno z ukrycia, kliknij widoczną część ukrytego okna lub przeciągnij ją. 
- Zmień rozmiar okna PIP, używając gestu uszczypnięcia. 
Aplikacja decyduje, kiedy bieżąca aktywność przechodzi w tryb obrazu w obrazie. Oto kilka przykładów:
- Aktywność może przejść w tryb obrazu w obrazie, gdy użytkownik naciśnie przycisk ekranu głównego lub przesunie palcem w górę do ekranu głównego. Dzięki temu Mapy Google mogą nadal wyświetlać wskazówki, gdy użytkownik wykonuje w tym samym czasie inne czynności. 
- Aplikacja może przenieść film do trybu obraz w obrazie, gdy użytkownik wróci z filmu, aby przeglądać inne treści. 
- Aplikacja może przełączyć film w tryb obrazu w obrazie, gdy użytkownik ogląda koniec odcinka. Na ekranie głównym wyświetlają się informacje promocyjne lub podsumowujące dotyczące następnego odcinka serialu. 
- Aplikacja może umożliwiać użytkownikom dodawanie do kolejki dodatkowych treści podczas oglądania filmu. Film będzie nadal odtwarzany w trybie obrazu w obrazie, a na ekranie głównym będzie wyświetlana aktywność wyboru treści. 
Deklarowanie obsługi trybu obraz w obrazie
Domyślnie system nie obsługuje automatycznie trybu obrazu w obrazie w przypadku aplikacji. Jeśli chcesz, aby Twoja aplikacja obsługiwała tryb obrazu w obrazie, zarejestruj aktywność związaną z wideo w pliku manifestu, ustawiając wartość android:supportsPictureInPicture na true. Określ też, że Twoja aktywność obsługuje zmiany konfiguracji układu, aby nie była ponownie uruchamiana, gdy podczas przejść do trybu obrazu w obrazie nastąpią zmiany układu.
<activity android:name="VideoActivity"
    android:supportsPictureInPicture="true"
    android:configChanges=
        "screenSize|smallestScreenSize|screenLayout|orientation"
    ...
Przełączanie aktywności na tryb obrazu w obrazie
Od Androida 12 możesz przełączyć aktywność w tryb obrazu w obrazie, ustawiając flagę setAutoEnterEnabled na true. Dzięki temu ustawieniu aktywność automatycznie przełącza się w tryb obrazu w obrazie w razie potrzeby bez konieczności jawnego wywoływania enterPictureInPictureMode() w onUserLeaveHint. Dodatkową korzyścią jest płynniejsze przechodzenie między scenami. Więcej informacji znajdziesz w artykule Płynniejsze przechodzenie do trybu obrazu w obrazie podczas nawigacji gestami.
Jeśli kierujesz reklamy na Androida 11 lub starszego, aktywność musi wywoływać
enterPictureInPictureMode()
aby przełączyć się na tryb obrazu w obrazie. Na przykład poniższy kod przełącza aktywność w tryb obrazu w obrazie, gdy użytkownik kliknie w interfejsie aplikacji specjalny przycisk:
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 uwzględnić logikę, która przełącza aktywność w tryb obrazu w obrazie zamiast przenosić ją w tle. Na przykład Mapy Google przełączają się w tryb obrazu w obrazie, gdy użytkownik naciśnie przycisk Początek lub Ostatnie podczas nawigacji w aplikacji. Możesz obsłużyć 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 płynne przejście do trybu obrazu w obrazie
W Androidzie 12 wprowadziliśmy znaczące zmiany wizualne w animowanych przejściach między oknami pełnoekranowymi a oknami w trybie obraz w obrazie. Zdecydowanie zalecamy wprowadzenie wszystkich odpowiednich zmian. Po ich wprowadzeniu zostaną one automatycznie dostosowane do dużych ekranów, takich jak urządzenia składane i tablety, bez konieczności wykonywania dodatkowych czynności.
Jeśli Twoja aplikacja nie zawiera odpowiednich aktualizacji, przejścia do trybu „obraz w obrazie” nadal będą działać, ale animacje będą mniej dopracowane. Na przykład przejście z trybu pełnoekranowego do trybu obrazu w obrazie może spowodować zniknięcie okna obrazu w obrazie podczas przejścia, zanim pojawi się ponownie po zakończeniu przejścia.
Zmiany te obejmują:
- Płynniejsze przechodzenie do trybu obrazu w obrazie podczas korzystania z nawigacji przy użyciu gestów
- Ustawienie odpowiedniego sourceRectHintdo włączania i wyłączania trybu obrazu w obrazie
- Wyłączanie płynnej zmiany rozmiaru w przypadku treści innych niż filmy
Aby uzyskać więcej informacji o włączaniu płynnego przejścia, zapoznaj się z przykładem Kotlin PictureInPicture na Androidzie.
Płynniejsze przechodzenie do trybu obrazu w obrazie podczas korzystania z nawigacji przy użyciu gestów
Od Androida 12 flaga setAutoEnterEnabled zapewnia znacznie płynniejszą animację podczas przechodzenia do treści wideo w trybie obrazu w obrazie za pomocą nawigacji gestami, np. podczas przesuwania palcem w górę do ekranu głównego z trybu pełnoekranowego.
Aby wprowadzić tę zmianę, wykonaj te czynności. W celu uzyskania dodatkowych informacji zapoznaj się z tym przykładem:
- Użyj - setAutoEnterEnabled, aby utworzyć- 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()); 
- Zadzwoń do - setPictureInPictureParamsz aktualnym numerem- PictureInPictureParamsz wyprzedzeniem. Aplikacja nie czeka na wywołanie zwrotne- onUserLeaveHint(jak w Androidzie 11).- Możesz na przykład wywołać funkcję - setPictureInPictureParamsprzy pierwszym odtworzeniu i przy każdym kolejnym odtworzeniu, jeśli zmieni się format obrazu.
- Wywołuj funkcję - setAutoEnterEnabled(false)tylko wtedy, gdy jest to konieczne. Na przykład nie chcesz włączać trybu PIP, jeśli odtwarzanie jest wstrzymane.
Ustaw odpowiedni sourceRectHint do włączania i wyłączania trybu obrazu w obrazie
Od wprowadzenia funkcji Obraz w obrazie w Androidzie 8.0 parametr setSourceRectHint
wskazywał obszar aktywności widoczny po przejściu do trybu obrazu w obrazie, np. granice widoku filmu w odtwarzaczu wideo.
W Androidzie 12 system używa sourceRectHint, aby zapewnić znacznie płynniejszą animację zarówno podczas włączania, jak i wyłączania trybu obraz w obrazie.
Aby prawidłowo ustawić sourceRectHint do włączania i wyłączania trybu obrazu w obrazie:
- Skonstruuj - PictureInPictureParams, używając odpowiednich granic jako- sourceRectHint. Zalecamy też dołączenie do odtwarzacza wideo detektora zmiany układu:- 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); 
- W razie potrzeby zaktualizuj - sourceRectHint, zanim system rozpocznie przejście do stanu wyjścia. Gdy system ma wyjść z trybu obrazu w obrazie, hierarchia widoków aktywności jest układana w konfiguracji docelowej (np. na pełnym ekranie). Aplikacja może dołączyć detektor zmiany układu do widoku głównego lub widoku docelowego (np. widoku odtwarzacza wideo), aby wykrywać zdarzenie i aktualizować wartość- sourceRectHintprzed 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łączanie płynnej zmiany rozmiaru w przypadku treści innych niż filmy
Android 12 dodaje flagę setSeamlessResizeEnabled, która zapewnia znacznie płynniejszą animację przenikania podczas zmiany rozmiaru treści innych niż wideo w oknie obrazu w obrazie. Wcześniej zmiana rozmiaru treści innych niż wideo w oknie obrazu w obrazie mogła powodować nieprzyjemne artefakty wizualne.
Aby włączyć płynną zmianę rozmiaru treści wideo:
Kotlin
setPictureInPictureParams(PictureInPictureParams.Builder() .setSeamlessResizeEnabled(true) .build())
Java
setPictureInPictureParams(new PictureInPictureParams.Builder() .setSeamlessResizeEnabled(true) .build());
Obsługa interfejsu podczas korzystania z trybu obrazu w obrazie
Gdy aktywność wchodzi w tryb obraz w obrazie lub z niego wychodzi, system wywołuje metodę Activity.onPictureInPictureModeChanged() lub Fragment.onPictureInPictureModeChanged().
W Androidzie 15 wprowadzono zmiany, które zapewniają jeszcze płynniejsze przejście do trybu obrazu w obrazie. Jest to przydatne w przypadku aplikacji, które mają elementy interfejsu użytkownika nakładane na główny interfejs użytkownika, który przechodzi w tryb obrazu w obrazie.
Deweloperzy używają wywołania zwrotnego onPictureInPictureModeChanged() do zdefiniowania logiki, która przełącza widoczność nakładanych elementów interfejsu. 
To wywołanie zwrotne jest wywoływane po zakończeniu animacji wejścia lub wyjścia z trybu obrazu w obrazie. 
Od Androida 15 klasa PictureInPictureUiState zawiera nowy stan.
W tym nowym stanie interfejsu aplikacje kierowane na Androida 15 obserwują wywołanie wywołania zwrotnego Activity#onPictureInPictureUiStateChanged() 
z wartością isTransitioningToPip() natychmiast po rozpoczęciu animacji obrazu w obrazie. 
Wiele elementów interfejsu nie jest istotnych dla aplikacji w trybie obrazu w obrazie, np. widoki lub układy zawierające informacje takie jak sugestie, nadchodzące filmy, oceny i tytuły. Gdy aplikacja przejdzie w tryb obrazu w obrazie, użyj wywołania zwrotnego onPictureInPictureUiStateChanged(), aby ukryć te elementy interfejsu. Gdy aplikacja przechodzi do trybu pełnoekranowego z okienka obrazu w obrazie, użyj wywołania zwrotnego onPictureInPictureModeChanged(), aby odkryć te elementy, jak pokazano w przykładach poniżej:
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. } }
Szybkie przełączanie widoczności nieistotnych elementów interfejsu (w przypadku okna obrazu w obrazie) pomaga zapewnić płynniejszą animację wejścia w tryb obrazu w obrazie bez migotania.
Zastąp te wywołania zwrotne, aby ponownie narysować elementy interfejsu aktywności. Pamiętaj, że w trybie obrazu w obrazie Twoja aktywność jest wyświetlana w małym oknie. Użytkownicy nie mogą wchodzić w interakcje z elementami interfejsu aplikacji, gdy jest ona w trybie obrazu w obrazie, a szczegóły małych elementów interfejsu mogą być trudne do zobaczenia. Odtwarzanie filmów z minimalnym interfejsem zapewnia najlepszą wygodę.
Jeśli Twoja aplikacja musi udostępniać niestandardowe działania w trybie obrazu w obrazie, zapoznaj się z sekcją Dodawanie elementów sterujących na tej stronie. Usuń inne elementy interfejsu przed przejściem działania do trybu obrazu w obrazie i przywróć je, gdy działanie ponownie zajmie cały ekran.
Dodaj elementy sterujące
Gdy użytkownik otworzy menu okna (dotykając okna na urządzeniu mobilnym lub wybierając menu na pilocie telewizora), mogą się w nim pojawić elementy sterujące.
Jeśli aplikacja ma aktywną sesję multimedialną, pojawią się elementy sterujące odtwarzaniem, wstrzymywaniem, następnym i poprzednim.
Możesz też jawnie określić działania niestandardowe, tworząc
PictureInPictureParams
za pomocą
PictureInPictureParams.Builder.setActions()
przed wejściem w tryb obrazu w obrazie i przekazując parametry podczas włączania tego trybu za pomocą
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ę.
Kontynuowanie odtwarzania filmu w trybie obraz w obrazie
Gdy aktywność przechodzi w tryb obrazu w obrazie, system umieszcza ją w stanie wstrzymania i wywołuje metodę onPause() aktywności. Odtwarzanie wideo nie powinno być wstrzymywane, ale powinno być kontynuowane, jeśli aktywność zostanie wstrzymana podczas przechodzenia do trybu obrazu w obrazie.
W Androidzie 7.0 i nowszych należy wstrzymywać i wznawiać odtwarzanie wideo, gdy system wywołuje metody aktywności onStop() i onStart(). Dzięki temu nie musisz sprawdzać, czy aplikacja jest w trybie obrazu w obrazie w onPause(), i wyraźnie kontynuować odtwarzania.
Jeśli nie ustawisz flagi setAutoEnterEnabled na true i musisz wstrzymać odtwarzanie w implementacji onPause(), sprawdź tryb obrazu w obrazie, wywołując isInPictureInPictureMode(), i odpowiednio obsłuż 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ść przejdzie z trybu obrazu w obrazie z powrotem do trybu pełnoekranowego, system wznowi aktywność i wywoła metodę onResume().
Używanie jednej aktywności odtwarzania w trybie obraz w obrazie
W aplikacji użytkownik może wybrać nowy film podczas przeglądania treści na ekranie głównym, gdy aktywność odtwarzania filmu jest w trybie obrazu w obrazie. Odtwórz nowy film w ramach istniejącej aktywności odtwarzania w trybie pełnoekranowym, zamiast uruchamiać nową aktywność, która może zmylić użytkownika.
Aby mieć pewność, że do żądań odtwarzania wideo jest używana jedna aktywność, która w razie potrzeby przełącza się w tryb obrazu w obrazie i z niego wychodzi, ustaw w pliku manifestu atrybut android:launchMode aktywności na singleTask:
<activity android:name="VideoActivity"
    ...
    android:supportsPictureInPicture="true"
    android:launchMode="singleTask"
    ...
W aktywności zastąp
onNewIntent()
i obsłuż nowy film, w razie potrzeby zatrzymując odtwarzanie bieżącego filmu.
Sprawdzone metody
Funkcja obrazu w obrazie może być wyłączona na urządzeniach z niewielką ilością pamięci RAM. Zanim aplikacja zacznie korzystać z trybu obrazu w obrazie, sprawdź, czy jest on dostępny, wywołując metodę hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE).
Tryb obrazu w obrazie jest przeznaczony do aktywności, które odtwarzają wideo na pełnym ekranie. Podczas przełączania aktywności w tryb obrazu w obrazie unikaj wyświetlania czegokolwiek poza treściami wideo. Śledź, kiedy aktywność przechodzi w tryb obrazu w obrazie, i ukrywaj elementy interfejsu zgodnie z opisem w sekcji Obsługa interfejsu podczas korzystania z trybu obrazu w obrazie.
Gdy aktywność jest w trybie obrazu w obrazie, domyślnie nie otrzymuje fokusu wejściowego. Aby otrzymywać zdarzenia wejściowe w trybie obrazu w obrazie, użyj MediaSession.setCallback().
Więcej informacji o używaniu setCallback() znajdziesz w artykule Wyświetlanie karty „Teraz odtwarzane”.
Gdy aplikacja jest w trybie obraz w obrazie, odtwarzanie wideo w oknie obrazu w obrazie może powodować zakłócenia dźwięku w innej aplikacji, np. w odtwarzaczu muzyki lub aplikacji do wyszukiwania głosowego. Aby tego uniknąć, poproś o skupienie dźwięku, gdy zaczniesz odtwarzać film, i obsługuj powiadomienia o zmianie skupienia dźwięku zgodnie z opisem w artykule Zarządzanie skupieniem dźwięku. Jeśli w trybie obrazu w obrazie otrzymasz powiadomienie o utracie fokusu dźwięku, wstrzymaj lub zatrzymaj odtwarzanie filmu.
Gdy aplikacja ma przejść do trybu obrazu w obrazie, tylko aktywność na górze ekranu przechodzi do tego trybu. W niektórych sytuacjach, np. na urządzeniach z wieloma oknami, aktywność poniżej może być teraz widoczna i ponownie pojawić się obok aktywności w trybie obraz w obrazie. W takim przypadku należy podjąć odpowiednie działania, w tym wywołać funkcję zwrotną onResume() lub onPause(). Użytkownik może też wchodzić w interakcje z aktywnością. Jeśli na przykład wyświetlasz aktywność listy filmów i aktywność odtwarzania filmu w trybie obraz w obrazie, użytkownik może wybrać nowy film z listy, a aktywność w trybie obraz w obrazie powinna się odpowiednio zaktualizować.
Dodatkowy przykładowy kod
Aby pobrać przykładową aplikację napisaną w języku Kotlin, zobacz Android PictureInPicture Sample (Kotlin) (w języku angielskim).
 
  