Videos mit Bild im Bild (BiB) hinzufügen

Compose ausprobieren
Jetpack Compose ist das empfohlene UI-Toolkit für Android. Informationen zum Unterstützen des Bild-im-Bild-Modus in der Google Messages App

Ab Android 8.0 (API-Ebene 26) können Aktivitäten in Android im Bild-im-Bild-Modus (PiP) gestartet werden. Der PiP-Modus ist ein spezieller Multifenstermodus, der hauptsächlich für die Videowiedergabe verwendet wird. Nutzer können sich ein Video in einem kleinen Fenster ansehen, das an einer Ecke des Bildschirms angepinnt ist, während sie zwischen Apps wechseln oder Inhalte auf dem Hauptbildschirm durchsuchen.

Für die Funktion „Bild-im-Bild“ werden die Mehrfenster-APIs genutzt, die in Android 7.0 verfügbar gemacht wurden, um das angepinnte Video-Overlay-Fenster bereitzustellen. Wenn Sie Ihrer App PiP hinzufügen möchten, müssen Sie die Aktivitäten registrieren, die PiP unterstützen, die Aktivität bei Bedarf in den PiP-Modus umschalten und dafür sorgen, dass die UI-Elemente ausgeblendet sind und die Videowiedergabe fortgesetzt wird, wenn die Aktivität im PiP-Modus ist.

Das PiP-Fenster wird in der obersten Ebene des Bildschirms in einer vom System ausgewählten Ecke angezeigt.

PiP wird auch auf kompatiblen Android TV-Geräten mit Android 14 (API-Level 34) oder höher unterstützt. Es gibt zwar viele Ähnlichkeiten, aber bei der Verwendung von PiP auf dem Fernseher gibt es zusätzliche Aspekte zu beachten.

Interaktionsmöglichkeiten der Nutzer mit dem PiP-Fenster

Nutzer können das PiP-Fenster an eine andere Stelle ziehen. Ab Android 12 haben Nutzer außerdem folgende Möglichkeiten:

  • Tippen Sie einmal auf das Fenster, um eine Vollbildschaltfläche, eine Schaltfläche zum Schließen, eine Schaltfläche für die Einstellungen und benutzerdefinierte Aktionen Ihrer App (z. B. Wiedergabesteuerungen) aufzurufen.

  • Doppeltippen Sie auf das Fenster, um zwischen der aktuellen BiB-Größe und der maximalen oder minimalen BiB-Größe zu wechseln. Wenn Sie beispielsweise auf ein maximiertes Fenster doppeltippen, wird es minimiert. Das Gegenteil ist auch der Fall.

  • Ziehen Sie das Fenster zum linken oder rechten Displayrand, um es auszublenden. Wenn Sie das Fenster wieder einblenden möchten, tippen Sie entweder auf den sichtbaren Teil des minimierten Fensters oder ziehen Sie es heraus.

  • Ändern Sie die Größe des BiB-Fensters durch Zusammen- oder Auseinanderziehen.

Ihre App steuert, wann die aktuelle Aktivität in den PiP-Modus wechselt. Hier einige Beispiele:

  • Eine Aktivität kann in den PiP-Modus wechseln, wenn der Nutzer auf die Schaltfläche „Startseite“ tippt oder zum Startbildschirm wischt. So wird in Google Maps weiterhin eine Wegbeschreibung angezeigt, während der Nutzer gleichzeitig eine andere Aktivität ausführt.

  • Ihre App kann ein Video in den Bild-im-Bild-Modus versetzen, wenn der Nutzer vom Video zurückgeht, um andere Inhalte zu suchen.

  • Ihre App kann ein Video in den PiP-Modus umschalten, während sich ein Nutzer das Ende einer Folge ansieht. Auf dem Hauptbildschirm werden Werbe- oder Zusammenfassungsinformationen zur nächsten Folge der Serie angezeigt.

  • Ihre App kann Nutzern die Möglichkeit bieten, während der Wiedergabe eines Videos zusätzliche Inhalte der Wiedergabeliste hinzuzufügen. Das Video wird im PiP-Modus fortgesetzt, während auf dem Hauptbildschirm eine Aktivität zur Inhaltsauswahl angezeigt wird.

Unterstützung von PiP deklarieren

Standardmäßig unterstützt das System PiP für Apps nicht automatisch. Wenn Sie PiP in Ihrer App unterstützen möchten, registrieren Sie Ihre Videoaktivität in Ihrem Manifest, indem Sie android:supportsPictureInPicture auf true festlegen. Geben Sie außerdem an, dass Ihre Aktivität Änderungen an der Layoutkonfiguration verarbeitet, damit sie nicht neu gestartet wird, wenn beim Wechsel in den PiP-Modus Layoutänderungen auftreten.

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

Aktivität in PiP-Modus wechseln

Ab Android 12 können Sie die Aktivität in den PiP-Modus umschalten, indem Sie das Flag setAutoEnterEnabled auf true setzen. Bei dieser Einstellung wechselt eine Aktivität bei Bedarf automatisch in den PiP-Modus, ohne dass onUserLeaveHint enterPictureInPictureMode() explizit aufgerufen werden muss. Außerdem sind die Übergänge so viel flüssiger. Weitere Informationen finden Sie unter Übergangsanimationen zum PiP-Modus über die Gestennavigation optimieren.

Wenn Ihre App auf Android 11 oder niedriger ausgerichtet ist, muss eine Aktivität enterPictureInPictureMode() aufrufen, um in den PiP-Modus zu wechseln. Im folgenden Code wird beispielsweise eine Aktivität in den PiP-Modus geschaltet, wenn der Nutzer auf eine spezielle Schaltfläche in der App-Benutzeroberfläche klickt:

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

Sie können eine Logik einbinden, die eine Aktivität in den PiP-Modus umschaltet, anstatt sie in den Hintergrund zu verschieben. In Google Maps wird beispielsweise in den PiP-Modus gewechselt, wenn der Nutzer während der Navigation die Schaltfläche „Startseite“ oder „Letzte“ drückt. Sie können diesen Fall abfangen, indem Sie onUserLeaveHint() überschreiben:

Kotlin

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

Java

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

Empfohlen: Für eine reibungslose PiP-Übergangsfunktion sorgen

In Android 12 wurden die animierten Übergänge zwischen Vollbild- und PiP-Fenstern deutlich verbessert. Wir empfehlen Ihnen dringend, alle erforderlichen Änderungen vorzunehmen. Anschließend werden diese Änderungen automatisch auf große Bildschirme wie faltbare Smartphones und Tablets skaliert, ohne dass Sie weitere Maßnahmen ergreifen müssen.

Wenn Ihre App keine entsprechenden Updates enthält, funktionieren PiP-Übergänge weiterhin, die Animationen sind jedoch weniger ausgefeilt. Wenn du beispielsweise vom Vollbildmodus zum PiP-Modus wechselst, kann es passieren, dass das PiP-Fenster während des Übergangs verschwindet und erst nach Abschluss des Übergangs wieder angezeigt wird.

Diese Änderungen umfassen Folgendes:

  • Der Wechsel in den PiP-Modus über die Bedienung per Geste ist jetzt flüssiger.
  • Eine richtige sourceRectHint für den Wechsel in den PiP-Modus und den Ausstieg aus dem PiP-Modus festlegen
  • Automatische Größenanpassung für Inhalte ohne Video deaktivieren

Im Android-Kotlin-Beispiel für Picture-in-Picture finden Sie eine Referenz für eine reibungslose Umstellung.

Der Wechsel in den PiP-Modus über die Bedienung per Geste ist jetzt flüssiger.

Ab Android 12 sorgt das Flag setAutoEnterEnabled für eine viel flüssigere Animation beim Wechsel zu Videoinhalten im PiP-Modus über die Gestennavigation, z. B. wenn Sie vom Vollbildmodus zum Startbildschirm wischen.

Führen Sie die folgenden Schritte aus, um diese Änderung vorzunehmen. Sehen Sie sich zur Veranschaulichung dieses Beispiel an:

  1. Mit setAutoEnterEnabled können Sie PictureInPictureParams.Builder erstellen:

    Kotlin

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

    Java

    setPictureInPictureParams(new PictureInPictureParams.Builder()
        .setAspectRatio(aspectRatio)
        .setSourceRectHint(sourceRectHint)
        .setAutoEnterEnabled(true)
        .build());
  2. Rufen Sie setPictureInPictureParams mit dem aktuellen PictureInPictureParams an. Die App wartet nicht auf den onUserLeaveHint-Callback (wie es unter Android 11 der Fall gewesen wäre).

    Du kannst setPictureInPictureParams beispielsweise bei der allerersten Wiedergabe und bei jeder weiteren Wiedergabe aufrufen, wenn sich das Seitenverhältnis ändert.

  3. Rufen Sie setAutoEnterEnabled(false) nur an, wenn es unbedingt erforderlich ist. So möchtest du beispielsweise wahrscheinlich nicht in den Bild-im-Bild-Modus wechseln, wenn die aktuelle Wiedergabe pausiert ist.

Richtige sourceRectHint für den Wechsel in den und den Ausstieg aus dem PiP-Modus festlegen

Seit der Einführung von BiB in Android 8.0 gibt setSourceRectHint an, welcher Bereich der Aktivität nach dem Wechsel in den Bild-im-Bild-Modus sichtbar ist, z. B. die Videowiedergabegrenzen in einem Videoplayer.

Unter Android 12 verwendet das System sourceRectHint, um sowohl beim Aktivieren als auch beim Deaktivieren des PiP-Modus eine viel flüssigere Animation zu implementieren.

So legen Sie sourceRectHint richtig für den Wechsel in den und den Ausstieg aus dem PiP-Modus fest:

  1. Erstellen Sie PictureInPictureParams mit den richtigen Grenzen als sourceRectHint. Wir empfehlen außerdem, dem Videoplayer einen Layoutänderungs-Listener hinzuzufügen:

    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. Aktualisieren Sie bei Bedarf die sourceRectHint, bevor das System den Ausstiegsübergang startet. Wenn das System den PiP-Modus beenden wird, wird die Ansichtshierarchie der Aktivität in der Zielkonfiguration (z. B. Vollbild) angeordnet. Die App kann der Stamm- oder Zielansicht (z. B. der Videoplayeransicht) einen Listener für Layoutänderungen hinzufügen, um das Ereignis zu erkennen und sourceRectHint zu aktualisieren, bevor die Animation beginnt.

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

Automatische Größenanpassung für Inhalte ohne Video deaktivieren

In Android 12 wird das Flag setSeamlessResizeEnabled hinzugefügt, das eine viel flüssigere Cross-Fading-Animation beim Ändern der Größe von nicht videobasierten Inhalten im PiP-Fenster ermöglicht. Bisher konnte das Ändern der Größe von nicht-videobasierten Inhalten in einem PiB-Fenster zu störenden visuellen Artefakten führen.

So deaktivieren Sie die automatische Größenanpassung für Inhalte, die keine Videos sind:

Kotlin

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

Java

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

Benutzeroberfläche während der Wiedergabe im Bild-im-Bild-Modus

Wenn die Aktivität den Bild-im-Bild-Modus (PiP) betritt oder verlässt, ruft das System Activity.onPictureInPictureModeChanged() oder Fragment.onPictureInPictureModeChanged() auf.

Android 15 führt Änderungen ein, die für einen noch reibungsloseren Übergang in den PiP-Modus sorgen. Das ist für Apps mit UI-Elementen vor der Haupt-UI von Vorteil, die in PiP angezeigt werden.

Entwickler verwenden den Rückruf onPictureInPictureModeChanged(), um eine Logik zu definieren, mit der die Sichtbarkeit der überlagerten UI-Elemente umgeschaltet wird. Dieser Callback wird ausgelöst, wenn die Animation für den Beginn oder das Ende des PiP-Videos abgeschlossen ist. Ab Android 15 enthält die Klasse PictureInPictureUiState einen neuen Status.

Bei diesem neuen UI-Status wird in Apps, die auf Android 15 ausgerichtet sind, der Rückruf Activity#onPictureInPictureUiStateChanged() mit isTransitioningToPip() aufgerufen, sobald die PiP-Animation beginnt. Es gibt viele UI-Elemente, die für die App im PiP-Modus nicht relevant sind, z. B. Ansichten oder Layouts mit Informationen wie Vorschlägen, anstehenden Videos, Bewertungen und Titeln. Wenn die App in den PiP-Modus wechselt, verwende den onPictureInPictureUiStateChanged()-Callback, um diese UI-Elemente auszublenden. Wenn die App vom PiP-Fenster in den Vollbildmodus wechselt, kannst du diese Elemente mit dem onPictureInPictureModeChanged()-Callback wieder einblenden, wie in den folgenden Beispielen gezeigt:

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

Durch die schnelle Sichtbarkeitsschaltung irrelevanter UI-Elemente (für ein PiP-Fenster) wird eine flüssigere und flackerfreie PiP-Einblendungsanimation ermöglicht.

Überschreiben Sie diese Callbacks, um die UI-Elemente der Aktivität neu zu zeichnen. Beachten Sie, dass Ihre Aktivitäten im PiP-Modus in einem kleinen Fenster angezeigt werden. Nutzer können nicht mit den UI-Elementen Ihrer App interagieren, wenn sich die App im PiP-Modus befindet. Außerdem sind die Details kleiner UI-Elemente möglicherweise schwer zu erkennen. Videowiedergabeaktivitäten mit einer minimalen Benutzeroberfläche bieten die beste Nutzerfreundlichkeit.

Wenn Ihre App benutzerdefinierte Aktionen für PiP bereitstellen muss, lesen Sie den Abschnitt Steuerelemente hinzufügen auf dieser Seite. Entfernen Sie andere UI-Elemente, bevor die Aktivität in den PiP-Modus wechselt, und stellen Sie sie wieder her, wenn die Aktivität wieder im Vollbildmodus angezeigt wird.

Steuerelemente hinzufügen

Im PiP-Fenster können Steuerelemente angezeigt werden, wenn der Nutzer das Menü des Fensters öffnet, indem er auf einem Mobilgerät auf das Fenster tippt oder das Menü über die TV-Fernbedienung auswählt.

Wenn für eine App eine aktive Mediensitzung vorliegt, werden die Steuerelemente „Wiedergabe“, „Pause“, „Weiter“ und „Zurück“ angezeigt.

Sie können auch benutzerdefinierte Aktionen explizit angeben, indem Sie PictureInPictureParams mit PictureInPictureParams.Builder.setActions() erstellen, bevor Sie den PiP-Modus aktivieren, und die Parameter übergeben, wenn Sie den PiP-Modus mit enterPictureInPictureMode(android.app.PictureInPictureParams) oder setPictureInPictureParams(android.app.PictureInPictureParams) aktivieren. Sei vorsichtig. Wenn Sie versuchen, mehr als getMaxNumPictureInPictureActions() hinzuzufügen, wird nur die maximale Anzahl angezeigt.

Videowiedergabe in der Bild-im-Bild-Funktion fortsetzen

Wenn die Aktivität in den PiP-Modus wechselt, setzt das System die Aktivität in den Pausierstatus und ruft die Methode onPause() der Aktivität auf. Die Videowiedergabe sollte nicht pausiert werden, sondern fortgesetzt werden, wenn die Aktivität beim Wechsel in den PiP-Modus pausiert wird.

Unter Android 7.0 und höher sollten Sie die Videowiedergabe pausieren und fortsetzen, wenn das System die onStop()- und onStart()-Methoden Ihrer Aktivität aufruft. So müssen Sie nicht prüfen, ob sich Ihre App in onPause() im PiP-Modus befindet, und die Wiedergabe nicht manuell fortsetzen.

Wenn du das Flag setAutoEnterEnabled nicht auf true gesetzt hast und die Wiedergabe in deiner onPause()-Implementierung pausieren möchtest, prüfe mit einem Aufruf von isInPictureInPictureMode(), ob der PiP-Modus aktiv ist, und handel entsprechend. Beispiel:

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

Wenn die Aktivität aus dem PiP-Modus in den Vollbildmodus wechselt, setzt das System die Aktivität fort und ruft die Methode onResume() auf.

Eine einzelne Wiedergabeaktivität für PiP verwenden

In Ihrer App kann ein Nutzer ein neues Video auswählen, während er auf dem Hauptbildschirm nach Inhalten sucht und eine Videowiedergabe im Bild-im-Bild-Modus läuft. Spielen Sie das neue Video in der vorhandenen Wiedergabeaktivität im Vollbildmodus ab, anstatt eine neue Aktivität zu starten, die den Nutzer verwirren könnte.

Damit für Videowiedergabeanfragen immer dieselbe Aktivität verwendet wird und der PiP-Modus bei Bedarf aktiviert oder deaktiviert wird, setzen Sie in Ihrem Manifest die android:launchMode der Aktivität auf singleTask:

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

Überschreiben Sie in Ihrer Aktivität onNewIntent() und verarbeiten Sie das neue Video. Beenden Sie bei Bedarf die Wiedergabe des vorhandenen Videos.

Best Practices

Auf Geräten mit wenig RAM ist PiP möglicherweise deaktiviert. Bevor Sie PiP in Ihrer App verwenden, prüfen Sie, ob es verfügbar ist. Rufen Sie dazu hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE) auf.

Der Bild-im-Bild-Modus ist für Aktivitäten gedacht, bei denen Videos im Vollbildmodus abgespielt werden. Wenn Sie die Aktivität in den PiP-Modus umschalten, sollten Sie nur Videoinhalte anzeigen. Sie können erfassen, wann Ihre Aktivität in den PiP-Modus wechselt, und UI-Elemente ausblenden, wie unter Behandlung der Benutzeroberfläche während des PiP-Modus beschrieben.

Wenn eine Aktivität im PiP-Modus ist, erhält sie standardmäßig nicht den Eingabefokus. Wenn du Eingabeereignisse im PiP-Modus erhalten möchtest, verwende MediaSession.setCallback(). Weitere Informationen zur Verwendung von setCallback() findest du unter Now Playing-Card anzeigen.

Wenn sich Ihre App im Bild-im-Bild-Modus befindet, kann die Videowiedergabe im Bild-im-Bild-Fenster zu Audiostörungen bei einer anderen App führen, z. B. bei einer Musikplayer-App oder einer Sprachsuch-App. Um dies zu vermeiden, fordern Sie den Audiofokus an, wenn Sie die Videowiedergabe starten, und verarbeiten Sie Benachrichtigungen zur Änderung des Audiofokus wie unter Audiofokus verwalten beschrieben. Wenn Sie im PiP-Modus eine Benachrichtigung zum Verlust des Audiofokus erhalten, pausieren oder beenden Sie die Videowiedergabe.

Wenn Ihre App demnächst in den Bild-im-Bild-Modus wechselt, wird nur die oberste Aktivität in diesem Modus angezeigt. In einigen Fällen, z. B. auf Geräten mit mehreren Fenstern, wird die Aktivität darunter jetzt angezeigt und ist neben der PiP-Aktivität wieder sichtbar. Du solltest diesen Fall entsprechend behandeln, einschließlich der Aktivität unten, bei der du einen Rückruf von onResume() oder onPause() erhältst. Es ist auch möglich, dass der Nutzer mit der Aktivität interagiert. Wenn beispielsweise eine Aktivität für eine Videoliste und die Wiedergabe eines Videos im PiP-Modus angezeigt werden, kann der Nutzer ein neues Video aus der Liste auswählen. Die PiP-Aktivität sollte sich entsprechend aktualisieren.

Zusätzlicher Beispielcode

Eine in Kotlin geschriebene Beispiel-App finden Sie unter Android PictureInPicture Sample (Kotlin).