ピクチャー イン ピクチャー(PIP)を使って動画を追加する

Android 8.0(API レベル 26)以降では、アクティビティをピクチャー イン ピクチャー(PIP)モードで起動できます。PIP は特別なタイプのマルチウィンドウ モードで、主に動画の再生に使用されます。ユーザーは、メイン画面でアプリ間を移動したりコンテンツをブラウジングしたりしながら、画面の隅に固定された小さなウィンドウで動画を視聴し続けることができます。

PIP は、Android 7.0 で使用可能になったマルチウィンドウ API を利用して、固定された動画オーバーレイ ウィンドウを提供します。アプリで PIP を使用するには、PIP をサポートするアクティビティを登録し、必要に応じてアクティビティを PIP モードに切り替える必要があります。そして、アクティビティが PIP モードのときには、UI 要素を非表示にして動画の再生を継続するようにします。

PIP ウィンドウが画面の最上位レイヤ( 制御します。

PIP は、 Android 14(API レベル 34)以降。類似点は多数ありますが、 使用する際の追加の考慮事項 テレビでの PIP

ユーザーが PIP ウィンドウを操作する方法

ユーザーは、PIP ウィンドウを別の位置にドラッグできます。Android 12 以降では、次のことも行えます。

  • PIP ウィンドウをシングルタップすると、全画面表示への切り替え、閉じるボタン、設定ボタン、アプリが提供するカスタム アクション(再生コントロールなど)が表示されます。

  • 現在の PIP サイズと最大サイズを切り替えるには、ウィンドウをダブルタップします または最小 PIP サイズ(最大化されたウィンドウのダブルタップなど) 最小化され、その逆も同様です。

  • ウィンドウを左端または右端にドラッグすると、ウィンドウが閉じます。パソコンの 閉じたウィンドウの見えている部分をタップするか、ドラッグしてウィンドウを開きます。

  • ピンチ操作で PIP ウィンドウのサイズを変更できます。

現在のアクティビティが PIP モードに入るタイミングは、アプリで制御します。次に例を示します。

  • ユーザーがホームボタンをタップするか、スワイプすると、アクティビティを PIP モードに切り替えることができます。 自宅まで届きます。このように Google マップでは ユーザーが別のアクティビティを同時に実行した場合。

  • ユーザーが元のページに戻ったときに、動画を PIP モードに 他のコンテンツをブラウジングできます。

  • ユーザーが見ている動画コンテンツがエピソードの終盤に差し掛かったら、動画を PIP モードに切り替えます。メイン画面には、シリーズの次のエピソードに関する宣伝情報やあらすじを表示します。

  • ユーザーが動画を見ながら他のコンテンツをキューに追加できるようにします。メインの画面が再生されても、動画は PIP モードで再生され続けます。 コンテンツ選択アクティビティが表示されている画面。

PIP サポートを宣言する

デフォルトでは、システムはアプリの PIP を自動的にサポートしません。目標 アプリで PIP をサポートするには、 android:supportsPictureInPicturetrue に設定します。また 新しい P-MAX キャンペーンを アクティビティがレイアウト設定の変更を処理するため、 PIP モードの遷移中にレイアウト変更が発生したときに再起動するようにしました。

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

アクティビティを PIP に切り替える

Android 12 以降では、以下を設定してアクティビティを PIP モードに切り替えることができます。 setAutoEnterEnabled フラグを true に設定します。この設定では、アクティビティは 明示的に呼び出しなくても、必要に応じて自動的に PIP モードに切り替わります onUserLeaveHintenterPictureInPictureMode()。ここには 非常にスムーズな遷移を実現できるという 利点もあります詳細については、Maker ジェスチャー ナビゲーションから PIP モードへのスムーズな遷移

Android 11 以前をターゲットとする場合、アクティビティで呼び出す必要があります。 enterPictureInPictureMode() PIP モードに切り替えますたとえば、次のコードは、アクティビティを ユーザーがアプリの UI で専用ボタンをクリックしたときの PIP モード:

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

アクティビティを PIP モードに切り替えるロジックを組み込むこともできます。 バックグラウンドに移りましょうたとえば、Google マップは、ユーザーがホームボタンまたは最近ボタンを押して別のアプリに移動すると、PIP モードに切り替わります。このようなケースをキャッチするには、次のように onUserLeaveHint() をオーバーライドします。

Kotlin

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

Java

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

推奨: 洗練された PIP 移行エクスペリエンスをユーザーに提供する

Android 12 では、アニメーション遷移の外観が大幅に改善されました 切り替えられますこれらをすべて実装することを強くおすすめします 変更が適用されるかどうか。これを行うと、これらの変更は自動的に 折りたたみ式やタブレットなどの大画面に対応できます。

アプリに適用可能なアップデートが含まれていない場合、PIP 移行は引き続き行われます。 機能しますが、アニメーションは洗練されていません。たとえば 全画面表示から PIP モードに切り替えると、再生中に PIP ウィンドウが消えることがあります。 遷移が再表示されます。

これらの変更には、次のものが含まれます。

  • ジェスチャー ナビゲーションから PIP モードへの移行をよりスムーズに
  • PIP モードの開始と終了のための適切な sourceRectHint の設定
  • 動画以外のコンテンツのシームレスなサイズ変更を無効にする

詳しくは、Android Kotlin の PictureInPicture のサンプル 移行のプロセスを洗練されたものにするためのリファレンスとしてご利用ください。

ジェスチャー ナビゲーションでの PIP モードへの遷移をよりスムーズにする

Android 12 以降では、setAutoEnterEnabled フラグにより、 ジェスチャーを使って PIP モードで動画コンテンツに遷移するスムーズなアニメーション たとえば、全画面表示から上にスワイプしてホームに移動したときなどです。

この変更を行うには、以下の手順を完了してください。こちらのサンプルを参考に、 参照:

  1. setAutoEnterEnabled を使用して構築する 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. 最新の PictureInPictureParams を使って、早い段階で setPictureInPictureParams を呼び出します。アプリは onUserLeaveHint コールバック(Android 11 と同様)。

    たとえば、最初に setPictureInPictureParams を呼び出す必要があるとします。 最初の再生と後続の再生(アスペクト比が変更された場合)

  3. setAutoEnterEnabled(false) を呼び出しますが、必要な場合のみ呼び出します。たとえば 現在の再生が一時停止中の場合、PIP に切り替える必要はありません。 あります。

PIP モードの開始と終了のための適切な sourceRectHint を設定

Android 8.0 での PIP の導入以降、setSourceRectHint は、遷移後に表示されるアクティビティの領域を示します。 (動画プレーヤーの動画視聴境界など)。

Android 12 では、システムは sourceRectHint を使用して、よりスムーズな実装を行います。 PIP モードの開始時と終了時の両方に表示されます。

PIP モードの開始と終了について sourceRectHint を適切に設定するには:

  1. PictureInPictureParams を構築する 適切な境界を sourceRectHint とします。また、Chronicle の 動画プレーヤーへのレイアウト変更リスナーを追加します。

    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. 必要に応じて、システムが起動する前に sourceRectHint を更新します。 終了遷移ですシステムが PIP モードを終了しようとすると、アクティビティの ビュー階層は、その宛先構成( クリックします。アプリでレイアウト変更リスナーをルートビューにアタッチできる またはターゲット ビュー(動画プレーヤーのビューなど)を使用してイベントを検出し、 アニメーションを開始する前に sourceRectHint を更新する。

    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());
        }
    });
    
    
で確認できます。

動画以外のコンテンツのシームレスなサイズ変更を無効にする

Android 12 では setSeamlessResizeEnabled フラグが追加されています。これにより、 PIP で動画以外のコンテンツのサイズを変更するときの、スムーズなクロスフェード アニメーション クリックします。以前は、PIP ウィンドウで動画以外のコンテンツのサイズを変更すると、 不快な視覚的なアーティファクトです。

動画以外のコンテンツのシームレスなサイズ変更を無効にするには、次のようにします。

Kotlin

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

Java

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

PIP 中の UI を処理する

アクティビティが PIP モードに入るか PIP モードを終了すると、システムは Activity.onPictureInPictureModeChanged() または Fragment.onPictureInPictureModeChanged()

アプリでは、これらのコールバックをオーバーライドして、アクティビティの UI 要素を再描画する必要があります。PIP モードでは、アクティビティを表示するウィンドウが小さいことに留意してください。アプリが PIP モードのため UI 要素が小さくて詳細が見づらいと、ユーザーはアプリの UI 要素を操作できません。動画再生アクティビティでは、UI の数を最小限にすることがユーザー エクスペリエンスの向上につながります。

アプリで PIP のカスタム アクションを提供する必要がある場合は、 管理する方法をご確認ください。他の UI 要素は、アクティビティを PIP に切り替える前に削除し、全画面表示に戻すときに復元するようにします。

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

コントロールを追加する

PIP ウィンドウでは、ユーザーが(モバイル デバイスでウィンドウをタップするか、テレビリモコンでメニューを選択することにより)ウィンドウのメニューを開いたときに、コントロールを表示できます。

アプリにアクティブなメディア セッション > 再生 一時停止、次へ、前のコントロールが表示されます。

カスタム アクションを明示的に指定するために、 PictureInPictureParams PictureInPictureParams.Builder.setActions() 設定し、PIP モードに入るとパラメータを渡すには、 enterPictureInPictureMode(android.app.PictureInPictureParams) または setPictureInPictureParams(android.app.PictureInPictureParams)。 ここで注意が必要なのは、getMaxNumPictureInPictureActions() を超える数のアクションを追加しようとしても、最大数のアクションしか追加できないという点です。

PIP の状態で動画再生を続行する

アクティビティが PIP に切り替わると、アクティビティは一時停止の状態になります。 アクティビティの onPause() メソッドを使用します。動画 アクティビティがない場合、再生を一時停止してはならず、代わりに再生を続行する PIP モードへの移行中に一時停止します。

Android 7.0 以降では、システムがアクティビティの onStop() または onStart() を呼び出したとき、アプリで動画再生の一時停止または再開を行う必要があります。これにより onPause() でアプリが PIP モードになっているかどうかを確認しなくても済むようになり、 明示的に続行する必要はありません。

setAutoEnterEnabled フラグを true に設定しておらず、 onPause() の実装で再生を一時停止するには、次を呼び出して PIP モードを確認します。 isInPictureInPictureMode() を使用して、再生を適切に処理します。例:

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

アクティビティが PIP モードから全画面モードに戻ると、システムは アクティビティが再開され、 onResume() メソッドを使用します。

PIP に対して単一の再生アクティビティを使用する

ユーザーがアプリ内でコンテンツをブラウジングしているときに、 動画再生アクティビティが PIP モードのときに、メイン画面に表示されます。新しい動画を再生 既存の再生アクティビティ内で、全画面表示モードを使用するのではなく、 ユーザーの混乱を招く可能性がある新しいアクティビティを除外します。

動画再生リクエストに単一のアクティビティが使用されるようにするため、 PIP モードのオンとオフを切り替えるには、アクティビティの android:launchMode を マニフェスト内の singleTask:

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

アクティビティでは、onNewIntent() をオーバーライドして新しい動画を処理し、必要に応じて既存の動画再生を停止します。

おすすめの方法

RAM が少ないデバイスでは、PIP が無効になっている場合があります。アプリで PIP を使用する前に、hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE) を呼び出して PIP が使用可能であることを確認してください。

PIP は、フルスクリーン動画を再生するアクティビティを対象としています。アクティビティを PIP モードに切り替えるときは、動画以外のコンテンツを表示しないようにしてください。トラッキングするタイミング UI の処理方法の説明に沿って、アクティビティが PIP モードになり、UI 要素が非表示になります。 配信します

アクティビティが PIP モードのとき、デフォルトでは入力フォーカスを取得しません。PIP モードのときに入力イベントを受信するには、MediaSession.setCallback() を使用します。setCallback() の使用方法について詳しくは、「この曲なに?」機能を表示するをご覧ください。 カード

アプリが PIP モードの場合、PIP ウィンドウで動画を再生すると音声が発生することがあります。 音楽プレーヤー アプリや音声検索アプリなど、他のアプリとの干渉を防ぐ。 これを回避するには、動画の再生開始時に音声フォーカスをリクエストし、 音声フォーカス変更通知(音声の管理 焦点。通知を受け取った場合 PIP モード時の音声フォーカス喪失の回数、動画再生を一時停止または停止できます。

アプリが PIP を開始しようとすると、上位のアクティビティのみが入ります。 使用できます。ある種の状況では(マルチウィンドウ デバイスなど)、下位のアクティビティが表示されて PIP アクティビティとともにユーザーに再表示される可能性があります。このようなケース(onResume() コールバックまたは onPause() コールバックを取得する下位のアクティビティなど)は、状況に応じて適切に処理する必要があります。また、ユーザーがアクティビティを操作する可能性もあります。たとえば、動画リストのアクティビティを表示状態にして、動画再生のアクティビティを PIP モードにした場合は、ユーザーがリストから新しい動画を選択したら、それに応じて PIP アクティビティを更新する必要があります。

他のサンプルコード

Kotlin で記述されたサンプルアプリをダウンロードするには、Android PictureInPicture サンプルをご覧ください。 (Kotlin)