J'essaie de montrer la vidéo de l'émission (.mp4) avec exoplayer dans RecyclerView et ViewPager. Je montre le contrôleur vidéo avec une disposition personnalisée. jusqu'ici tout va bien.
Essayez maintenant de faire un plein écran de la vidéo comme un autre lecteur vidéo, comment l'utiliser avant, mais ne peut pas trouver un bon moyen dans le document exoplayer.
quelqu'un peut-il m'aider?
La bibliothèque ExoPlayer ne fournit actuellement pas de méthode intégrée pour activer/désactiver le mode plein écran. Vous devez l'implémenter vous-même ou trouver du code tiers pour cela, je le crains.
Deux étapes sont essentiellement nécessaires :
a) Réglez les propriétés de la fenêtre et de l'activité en mode plein écran et/ou immersif et (si vous le souhaitez) passez en mode paysage. Ce n'est pas difficile. Voir cette page sur Android .
b) Rendu de transition vers un SimpleExoPlayerView
(en fait, il s'agit de la surface) qui couvre la fenêtre entière en mode immersif. Il s'agit davantage d'un défi pour obtenir une expérience utilisateur optimale à tous les niveaux d'API.
Pour une expérience utilisateur optimale, nous souhaitons que le lecteur continue de jouer tout en effectuant la transition vers le plein écran et vice-versa, pour continuer la lecture de manière transparente. Dans un RecyclerView, c'est un peu difficile à résoudre pour tous les niveaux d'API.
Approche 1
Le moyen le plus simple est probablement d'avoir une instance distincte de SimpleExoPlayerView que vous placez au-dessus de votre mise en page dès que vous êtes entré en mode immersif (certaines personnes ouvrent une boîte de dialogue avec la deuxième vue pour cela, certaines ont la deuxième vue simplement en haut dans la mise en page en quelque sorte et le montrer/cacher sur demande).
Ensuite, vous détachez l'instance de lecteur du SimpleExoPlayerView intégré dans le RV et l'attachez à la vue plein écran avec un appel à un méthode d'assistance statique :
SimpleExoPlayerView.switchTargetView(simpleExoPlayer, oldPlayerView, newPlayerView);
Cette approche fonctionne très bien sur API> = 23. Avec l'API 23, la méthode MediaCodec.setOutputSurface permettant d'échanger dynamiquement des surfaces a été ajoutée. La méthode statique ci-dessus garantit que cette technique est appliquée. En conséquence, l'audio et la vidéo continuent de jouer et l'expérience utilisateur d'entrer et de quitter le plein écran est super fluide. Pour l'API <= 22, une nouvelle instance de codec doit être créée pour passer à une autre surface. Cela interrompt la lecture et l'expérience utilisateur de cette approche est dégradée.
Approche 2
Pour éviter de passer à une autre surface à un niveau API inférieur, vous devez utiliser une seule surface et la faire passer en plein écran d'une manière ou d'une autre. Vous pouvez soit masquer tout le reste que SimpleExoPlayerView et définir la largeur et la hauteur de la mise en page pour qu'elle corresponde à son parent ou, vous pouvez remplacer la vue vidéo par un espace réservé et la mettre en haut et en arrière.
Cela peut très bien fonctionner pour les mises en page simples, mais avec des mises en page complexes comprenant probablement des fragments, des visualiseurs, des aperçus de recyclage, cela peut être une opération assez intrusive provoquant un scintillement ou une interruption de la lecture sous peu (sur certains niveaux d'API, par exemple lors de la suppression de la vue du lecteur de la hiérarchie des vues). ). J'ai cependant vu cela bien fonctionner pour diverses mises en page.
Autres approches/défis
Il peut y avoir d'autres approches et probablement meilleures lorsque vous creusez plus profondément et/ou si vous n'utilisez pas du tout SimpleExoPlayerView.
Vous pouvez utiliser cette bibliothèque si vous voulez un exoplayer FullScreen:
https://github.com/Norulab/Android-exoplayer-fullscreen
Cette bibliothèque contient quelques fonctions d'extensions pour ExoPlayer:
val player = SimpleExoPlayer.Builder(context).build()
player.preparePlayer(playerView)
player.setSource(applicationContext, "http://html5videoformatconverter.com/data/images/happyfit2.mp4")
Exoplayer ne fournit pas le plein écran, voici donc la solution de contournement qui a fonctionné pour moi. Ici, j'ai restreint la rotation de l'écran et la modification manuelle de l'orientation modifie par programme la largeur et la hauteur de la vue player_view et a réglé la visibilité de la barre d'outils. Utilisé Data Binding et Kotlin.
Suit un bloc de code pour 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>
Changements dans Android Manifest
<activity Android:name=".yourPackage.ClassName"
Android:screenOrientation="portrait"
Android:configChanges="orientation|screenSize|layoutDirection"/>
Vérifiez l'orientation et faites-la pivoter via le code suivant
mBinding.playerView.exo_fullscreen_btn.setOnClickListener {
if ((activity as TrainingVideoActivity).checkLandscapeOrientation()) {
(activity as TrainingVideoActivity).changeOrientationToLandscape(false)
} else {
(activity as TrainingVideoActivity).changeOrientationToLandscape(true)
}
}
Les méthodes Signature suivent
/**
* 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
}
Maintenant, remplacez simplement la méthode onConfigurationChanged dans votre fragment/activité, car ici j'ai utilisé Fragment. Ici, j'ai donc changé la largeur/hauteur du conteneur parent dans lequel ExoplayerView est placé.
/**
* 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)
}
Enfin, XML pour le player_controller
<?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>
Laissez-moi savoir si cela fonctionne.
Veillez à définir la longueur et la largeur de la vue du lecteur pour correspondre à son parent.
Utilisez ceci pour masquer la barre d'état: getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
Utilisez ceci pour masquer la barre de navigation: getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);
Vous pouvez régler le lecteur en plein écran en définissant les paramètres du lecteur.
Params params = (LinearLayout.LayoutParams)
exoPlayerView.getLayoutParams();
params.width=params.MATCH_PARENT;
params.height=params.MATCH_PARENT;
exoPlayerView.setLayoutParams(params);
}
Et cachez la barre d'action:
getWindow().requestFeature(Window.FEATURE_ACTION_BAR);
getActionBar().hide();
J'espère que cela pourra aider