RecyclerViewおよびViewPagerにexoplayerを使用してショービデオ(.mp4)を表示しようとしています。カスタムレイアウトのビデオコントローラーを表示します。ここまでは順調ですね。
今度は他のビデオプレーヤーと同じようにビデオを全画面表示してみてくださいexoplayerドキュメントで良い方法を見つけることができません。
誰かが私を助けてくれますか?
ExoPlayerライブラリは現在、フルスクリーンモードを有効/無効にする組み込みの方法を提供していません。これを自分で実装するか、このためのサードパーティのコードを見つける必要があります。
基本的に2つのステップが必要です:
a)ウィンドウとアクティビティのプロパティをフルスクリーンモードまたはイマーシブモードに設定し、(必要に応じて)横長モードに変更します。それは難しくありません。 Android Developers のこのページ)を参照してください。
b)イマーシブモードでビューポート全体をカバーするSimpleExoPlayerView
(実際はサーフェスに関するもの)へのレンダリングの遷移。これは、すべてのAPIレベルで最適なユーザーエクスペリエンスを実現するための課題です。
最適なユーザーエクスペリエンスを実現するために、全画面表示への移行中も再生中もプレーヤーを再生し続け、シームレスに再生を続けたいと考えています。 RecyclerViewでは、これはすべてのAPIレベルで解決するのが少し難しいです。
アプローチ1
最も簡単な方法は、おそらく、没入モードに入るとすぐにレイアウトの上に配置するSimpleExoPlayerViewの個別のインスタンスを作成することです(このための2番目のビューでダイアログを開く人もいれば、2番目のビューをレイアウトの一番上に置く人もいます)どういうわけか、オンデマンドでそれを表示/非表示にします)。
次に、RVに埋め込まれたSimpleExoPlayerViewからプレーヤーインスタンスをデタッチし、それを 静的ヘルパーメソッド への呼び出しでフルスクリーンビューにアタッチします。
SimpleExoPlayerView.switchTargetView(simpleExoPlayer, oldPlayerView, newPlayerView);
このアプローチは、API> = 23で非常にうまく機能します。 API 23では、メソッド MediaCodec.setOutputSurface が動的にサーフェスをスワップできるようになりました。上記の静的メソッドは、この手法が確実に適用されるようにします。その結果、オーディオとビデオは再生を続け、フルスクリーンに出入りするユーザーエクスペリエンスは非常にスムーズです。 API <= 22の場合、別のサーフェスにスワップするには、新しいコーデックインスタンスを作成する必要があります。これにより再生が中断され、このアプローチのユーザーエクスペリエンスが低下します。
アプローチ2
低いAPIレベルで別のサーフェスにスワップしないようにするには、単一のサーフェスを使用して、なんらかの方法でフルスクリーンに移行する必要があります。 SimpleExoPlayerView以外のすべてを非表示にして、レイアウトの幅と高さを親に一致するように設定するか、ビデオビューをプレースホルダーに置き換えて上下に配置することができます。
これは単純なレイアウトでは非常にうまく機能しますが、フラグメント、ビューページャー、リサイクラービューなどの複雑なレイアウトでは、非常に煩わしい操作になり、何かがちらついたり、再生がすぐに中断したりする可能性があります(たとえば、一部のAPIレベルでは、ビュー階層からプレーヤービューを削除する場合)。 )。これがさまざまなレイアウトでうまく機能するのを見てきました。
さらにアプローチ/課題
より深く掘り下げる場合や、SimpleExoPlayerViewをまったく使用しない場合は、他の、おそらくより優れたアプローチが考えられます。
FullScreen Exoplayerが必要な場合は、このライブラリを使用できます。
https://github.com/Norulab/Android-exoplayer-fullscreen
このライブラリには、ExoPlayerの拡張機能がいくつか含まれています。
val player = SimpleExoPlayer.Builder(context).build()
player.preparePlayer(playerView)
player.setSource(applicationContext, "http://html5videoformatconverter.com/data/images/happyfit2.mp4")
Exoplayerはフルスクリーンを提供しないので、ここで私のために働いた回避策があります。ここでは、画面の回転を制限し、方向を手動で変更して、player_viewの幅と高さをプログラムで変更し、ツールバーの表示を設定しました。データバインディングとKotlinを使用。
XMLのコードブロックに従います
<androidx.constraintlayout.widget.ConstraintLayout
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
Android:id="@+id/video_player_container"
Android:layout_width="match_parent"
Android:layout_height="250dp"
app:layout_constraintTop_toTopOf="parent">
<com.google.Android.exoplayer2.ui.SimpleExoPlayerView
Android:id="@+id/player_view"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:focusable="true"
Android:keepScreenOn="true"
Android:padding="0dp"
app:controller_layout_id="@layout/exo_playback_control_view"
app:layout_constraintTop_toTopOf="parent"
app:resize_mode="fill"
app:use_controller="true" />
<LinearLayout
Android:id="@+id/nextVideoContainer"
Android:layout_width="wrap_content"
Android:layout_height="@dimen/spacing_32"
Android:background="#90000000"
Android:onClick="@{() -> vm.onNextVideo()}"
Android:orientation="horizontal"
Android:paddingLeft="@dimen/spacing_16"
Android:paddingRight="@dimen/spacing_16"
Android:visibility="@{vm.shouldShowNextBtn}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.sharedcode.widgets.CustomTextView
Android:id="@+id/next_video_label"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_gravity="center_vertical"
Android:text="@string/label_next"
Android:textColor="@Android:color/white" />
<com.sharedcode.widgets.CustomImageView
Android:id="@+id/next_video_image"
Android:layout_width="10dp"
Android:layout_height="10dp"
Android:layout_gravity="center_vertical"
Android:layout_marginStart="8dp"
Android:layout_marginLeft="8dp"
Android:paddingTop="2dp"
Android:src="@drawable/ic_play_next" />
</LinearLayout>
<RelativeLayout
Android:id="@+id/retry_container"
Android:layout_width="0dp"
Android:layout_height="0dp"
Android:background="#90000000"
Android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
Android:onClick="@{() -> vm.onRetry()}">
<com.sharedcode.widgets.CustomTextView
Android:id="@+id/txt_no_internet"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_marginBottom="0dp"
Android:layout_centerInParent="true"
Android:text="@string/txt_no_internet_connection"
Android:textColor="@Android:color/white"
Android:textSize="@dimen/font_16" />
<com.sharedcode.widgets.CustomTextView
Android:layout_width="`wrap_content`"
Android:layout_height="wrap_content"
Android:layout_below="@+id/txt_no_internet"
Android:layout_centerInParent="true"
Android:layout_marginTop="@dimen/spacing_16"
Android:maxHeight="@dimen/spacing_32"
Android:text="@string/txt_tap_to_retry"
Android:textColor="@Android:color/white"
Android:textSize="@dimen/font_16" />
</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Androidマニフェストの変更
<activity Android:name=".yourPackage.ClassName"
Android:screenOrientation="portrait"
Android:configChanges="orientation|screenSize|layoutDirection"/>
向きを確認し、次のコードで回転させます
mBinding.playerView.exo_fullscreen_btn.setOnClickListener {
if ((activity as TrainingVideoActivity).checkLandscapeOrientation()) {
(activity as TrainingVideoActivity).changeOrientationToLandscape(false)
} else {
(activity as TrainingVideoActivity).changeOrientationToLandscape(true)
}
}
メソッドのシグネチャは次のとおりです
/**
* Changes the Orientation
* @param shouldLandscape
*/
fun changeOrientationToLandscape(shouldLandscape: Boolean) {
requestedOrientation = if (shouldLandscape) {
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
} else {
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
}
}
/**
* Checks the Orientation
* And returns true if Landscape else false
*/
fun checkLandscapeOrientation() : Boolean {
val orientation = resources.configuration.orientation
return orientation == Configuration.ORIENTATION_LANDSCAPE
}
ここでFragmentを使用しているため、フラグメント/アクティビティでonConfigurationChangedメソッドをオーバーライドするだけです。そこで、ExoplayerViewが配置される親コンテナーの幅/高さを変更しました。
/**
* Used for Showing Video on Full Screen
* @param newConfig
* Used EXO_PLAYER_VIEW_HEIGHT as 250
*/
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
hideToolbarAndShowFullScreen()
mBinding.playerView.exo_fullscreen_btn.setImageDrawable(ContextCompat.getDrawable(activity!!, R.drawable.ic_shrink))
val params = mBinding.videoPlayerContainer.layoutParams as ConstraintLayout.LayoutParams
params.width = ViewGroup.LayoutParams.MATCH_PARENT
params.height = ViewGroup.LayoutParams.MATCH_PARENT
mBinding.videoPlayerContainer.layoutParams = params
} else {
showToolbarAndClearFullScreen()
mBinding.playerView.exo_fullscreen_btn.setImageDrawable(ContextCompat.getDrawable(activity!!, R.drawable.ic_fullscreen))
val params = mBinding.videoPlayerContainer.layoutParams as ConstraintLayout.LayoutParams
val factor = mBinding.playerView.context.resources.displayMetrics.density
params.width = ViewGroup.LayoutParams.MATCH_PARENT
params.height = (EXO_PLAYER_VIEW_HEIGHT * factor).toInt()
mBinding.videoPlayerContainer.layoutParams = params
}
}
/**
* Show the Toolbar and reset to original in the Portrait Mode
*/
private fun showToolbarAndClearFullScreen() {
(activity as TrainingVideoActivity).supportActionBar!!.show()
(activity as TrainingVideoActivity).window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN)
}
最後に、player_controllerのXML
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<RelativeLayout xmlns:app="http://schemas.Android.com/apk/res-auto"
xmlns:tools="http://schemas.Android.com/tools"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:background="#99000000">
<LinearLayout
Android:id="@+id/container_play_pause"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_centerInParent="true"
Android:orientation="horizontal">
<ImageButton
Android:id="@id/exo_play"
style="@style/ExoMediaButton.Play"
Android:src="@drawable/ic_play_exoplayer"
/>
<ImageButton
Android:id="@id/exo_pause"
style="@style/ExoMediaButton.Pause"
Android:src="@drawable/ic_pause_exoplayer"/>
</LinearLayout>
<LinearLayout
Android:id="@+id/seekbar_bottom"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:layout_alignParentBottom="true"
Android:layout_gravity="bottom"
Android:background="#CC000000"
Android:clickable="false"
Android:orientation="vertical">
<LinearLayout
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:layout_marginTop="4dp"
Android:gravity="center_vertical"
Android:orientation="horizontal"
tools:ignore="UselessParent">
<com.sharedcode.widgets.CustomTextView
Android:id="@id/exo_position"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:includeFontPadding="false"
Android:paddingLeft="4dp"
Android:paddingRight="4dp"
Android:textColor="#FFBEBEBE"
Android:textSize="14sp"
Android:textStyle="bold" />
<com.bnb.paynearby.utils.exoplayer.ExtendedTimebar
Android:id="@id/exo_progress"
Android:layout_width="0dp"
Android:layout_height="50dp"
Android:layout_weight="1"
app:buffered_color="@color/white"
app:played_color="@color/color_red"
app:scrubber_color="@color/color_red"
app:scrubber_disabled_size="10dp"
app:unplayed_color="#484848" />
<com.sharedcode.widgets.CustomTextView
Android:id="@id/exo_duration"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:clickable="false"
Android:includeFontPadding="false"
Android:paddingLeft="4dp"
Android:paddingRight="4dp"
Android:textColor="#FFBEBEBE"
Android:textSize="14sp"
Android:textStyle="bold" />
<com.sharedcode.widgets.CustomImageView
Android:id="@+id/exo_fullscreen_btn"
Android:layout_width="24dp"
Android:layout_height="24dp"
Android:layout_margin="8dp"
Android:src="@drawable/ic_fullscreen"
/>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
これが機能するかどうか教えてください。
必ず、親と一致するようにプレーヤービューの長さと幅を設定してください。
これを使用してステータスバーを非表示にします:getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
これを使用して、ナビゲーションバーを非表示にします。getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
プレーヤーのパラメーターを設定することで、プレーヤーを全画面に設定できます。
Params params = (LinearLayout.LayoutParams)
exoPlayerView.getLayoutParams();
params.width=params.MATCH_PARENT;
params.height=params.MATCH_PARENT;
exoPlayerView.setLayoutParams(params);
}
アクションバーを非表示にします。
getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
getActionBar().hide();
それが役に立てば幸い