Android VideoView changement d'orientation avec tampon de la vidéo
Je suis en train de reproduire la fonctionnalité de la dernière application YouTube sur le marché Android. Lorsque vous regardez une vidéo il y a deux mises en page, un portrait, qui fournit des informations supplémentaires, et un paysage qui offre une vue plein écran de la vidéo.
YouTupe application en mode portrait
Application YouTube en mode paysage
(Désolé pour le caractère aléatoire des photos, mais elles ont été les premières photos que j'ai pu trouver de la disposition réelle)
C'est assez facile à faire, normalement il suffit de spécifier une autre mise en page mise en page-la terre et tout sera bon. La chose que l'application YouTube n'est vraiment bien (et ce que j'essaie de reproduire), c'est que sur le changement d'orientation, la vidéo continue à jouer et ne pas avoir à re-mémoire tampon à partir du début.
J'ai compris que primordial onConfigurationChange() et la définition de nouvelles LayoutParameters va me permettre de redimensionner la vidéo sans forcer un rebuffer - cependant la vidéo, de façon aléatoire, à l'échelle de différentes largeurs/hauteurs lors de la rotation de l'écran à plusieurs reprises. J'ai essayé de faire toutes sortes de invalidate() appelle la VideoView, essayé d'appeler RequestLayout() sur le parent RelativeLayout conteneur et juste essayer autant de choses différentes que je peux, mais je n'arrive pas à le faire fonctionner correctement. Tout conseil serait grandement apprécié!
Voici mon code:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
questionText.setVisibility(View.GONE);
respond.setVisibility(View.GONE);
questionVideo.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
} else {
questionText.setVisibility(View.VISIBLE);
respond.setVisibility(View.VISIBLE);
Resources r = getResources();
int height = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 150.0f, r.getDisplayMetrics());
questionVideo.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, height));
}
}
EDIT: je l'ai découvert dans le logcat certains intéressant de sortie qui arrive lorsque ma vidéo est tournée qui semble être le coupable, bien que je n'ai aucune idée de comment le résoudre:
Logcat de sortie lors d'un redimensionnement correctement (prend toute la fenêtre)
avis de l'h=726
12-13 15:37:35.468 1262 1270 I ActivityManager: Config changed: { scale=1.0 imsi=310/4 loc=en_US touch=3 keys=1/1/2 nav=1/1 orien=2 layout=34 uiMode=17 seq=210}
12-13 15:37:35.561 1262 1268 I TIOverlay: Position/X0/Y76/W480/H225
12-13 15:37:35.561 1262 1268 I TIOverlay: Adjusted Position/X1/Y0/W403/H225
12-13 15:37:35.561 1262 1268 I TIOverlay: Rotation/90
12-13 15:37:35.561 1262 1268 I Overlay : v4l2_overlay_set_position:: w=480 h=224
12-13 15:37:35.561 1262 1268 I Overlay : v4l2_overlay_set_position:: w=402 h=726
12-13 15:37:35.561 1262 1268 I Overlay : dumping driver state:
12-13 15:37:35.561 1262 1268 I Overlay : output pixfmt:
12-13 15:37:35.561 1262 1268 I Overlay : w: 432
12-13 15:37:35.561 1262 1268 I Overlay : h: 240
12-13 15:37:35.561 1262 1268 I Overlay : color: 7
12-13 15:37:35.561 1262 1268 I Overlay : UYVY
12-13 15:37:35.561 1262 1268 I Overlay : v4l2_overlay window:
12-13 15:37:35.561 1262 1268 I Overlay : window l: 1
12-13 15:37:35.561 1262 1268 I Overlay : window t: 0
12-13 15:37:35.561 1262 1268 I Overlay : window w: 402
12-13 15:37:35.561 1262 1268 I Overlay : window h: 726
Logcat de sortie lors d'un redimensionnement de manière incorrecte (prend la minuscule portion de plein écran)
avis de l'h=480
12-13 15:43:00.085 1262 1270 I ActivityManager: Config changed: { scale=1.0 imsi=310/4 loc=en_US touch=3 keys=1/1/2 nav=1/1 orien=2 layout=34 uiMode=17 seq=216}
12-13 15:43:00.171 1262 1268 I TIOverlay: Position/X0/Y76/W480/H225
12-13 15:43:00.171 1262 1268 I TIOverlay: Adjusted Position/X138/Y0/W266/H225
12-13 15:43:00.171 1262 1268 I TIOverlay: Rotation/90
12-13 15:43:00.179 1262 1268 I Overlay : v4l2_overlay_set_position:: w=480 h=224
12-13 15:43:00.179 1262 1268 I Overlay : v4l2_overlay_set_position:: w=266 h=480
12-13 15:43:00.179 1262 1268 I Overlay : dumping driver state:
12-13 15:43:00.179 1262 1268 I Overlay : output pixfmt:
12-13 15:43:00.179 1262 1268 I Overlay : w: 432
12-13 15:43:00.179 1262 1268 I Overlay : h: 240
12-13 15:43:00.179 1262 1268 I Overlay : color: 7
12-13 15:43:00.179 1262 1268 I Overlay : UYVY
12-13 15:43:00.179 1262 1268 I Overlay : v4l2_overlay window:
12-13 15:43:00.179 1262 1268 I Overlay : window l: 138
12-13 15:43:00.179 1262 1268 I Overlay : window t: 0
12-13 15:43:00.179 1262 1268 I Overlay : window w: 266
12-13 15:43:00.179 1262 1268 I Overlay : window h: 480
Peut-être quelqu'un sait ce que "Overlay" est et pourquoi il n'est pas obtenir la bonne hauteur de la valeur?
- Enfin obtenu ce travail en utilisant le nouveau Fragment de l'API et un TextureView, je sais que c'est une vieille question, mais j'ai posté ma solution ainsi donc, les gens pourraient voir le jour approche.
- Cette réponse qui fonctionne pour moi - une seule ligne de code, puisque je l'ai déjà sous-classe VideoView stackoverflow.com/a/22101290/1458948
Vous devez vous connecter pour publier un commentaire.
EDIT: (juin 2016)
Cette réponse est très ancienne (je pense que android 2.2/2.3) et n'est probablement pas aussi pertinents que les autres réponses ci-dessous! Regardez d'abord à eux, sauf si vous êtes dev-ing sur l'héritage Android 🙂
J'ai été en mesure de réduire le problème à la onMeasure fonction dans le VideoView classe. Par la création d'un enfant de la classe et en remplaçant la onMeasure fonction, j'ai été en mesure d'obtenir la fonctionnalité désirée.
Puis à l'intérieur de mon Activité j'ai juste fait la suivante:
La ligne:
est la clé pour faire ce travail. Si vous ne le setDimensions appel sans ce gars-là, la vidéo n'est toujours pas redimensionner.
La seule autre chose que vous devez faire est de vous assurer que vous appelez setDimensions() dans le onCreate() la méthode ainsi ou votre vidéo ne démarre pas de mise en mémoire tampon de la vidéo ne sera pas mis à dessiner sur une surface de n'importe quelle taille.
Une dernière clé partie - si jamais vous vous demandez pourquoi le VideoView n'est pas le redimensionnement rotation, vous devez vous assurer que les dimensions que vous êtes redimensionnement sont soit exactement égale à la zone visible ou moins d'elle. J'ai eu un gros problème quand j'étais réglage de la VideoView de la largeur/hauteur de l'ensemble de la taille de l'écran quand j'avais encore la barre de notification/barre de titre sur l'écran et il n'était pas le redimensionnement de la VideoView à tous. Tout simplement en enlevant la barre de notification et la barre de titre fixe le problème.
J'espère que cela aide quelqu'un dans le futur!
Ici est vraiment un moyen facile de réaliser ce que vous voulez avec un minimum de code:
AndroidManifest.xml:
Remarque: Modifier en tant que de besoin pour votre API, ce qui couvre 10+, mais la baisse des Api exiger le retrait du "screenSize|screenLayout|uiMode" la partie de cette ligne
À l'intérieur de la "OnCreate" la méthode, habituellement sous la "super.onCreate", ajouter:
Et puis, quelque part, généralement au bas, ajouter:
Cela permettra de redimensionner la vidéo en plein écran à chaque fois que l'orientation a changé sans interrompre la lecture et ne nécessite qu'une substitution de la méthode de configuration.
mediaController.hide()
fonction.Tout d'abord, merci beaucoup pour votre propre vaste réponse.
J'ai eu le même problème, la vidéo serait la plupart du temps, être plus petit ou plus grand, ou déformée à l'intérieur de la VideoView après une rotation.
J'ai essayé ta solution, mais j'ai aussi essayé le fruit du hasard, et par chance, j'ai remarqué que si mon VideoView est centré dans son parent, la magie fonctionne par lui-même (non personnalisés VideoView nécessaire ou quoi que ce soit).
Pour être plus précis, avec cette mise en page, je reproduis le problème la plupart du temps:
Avec cette mise en page, je n'ai jamais eu le problème (et en plus, la vidéo est centrée, ce qui est la façon dont il devrait être de toute façon ;):
Il travaille également avec
wrap_content
au lieu dematch_parent
(la vidéo prend tout l'espace) qui ne fait pas beaucoup de sens pour moi.De toute façon, je n'ai pas d'explication pour cela - cela ressemble à un VideoView bug pour moi.
VideoView utilise ce qu'on appelle une superposition qui est une zone où la vidéo est rendue. Cette superposition est derrière la fenêtre de la tenue de la VideoView. VideoView coups de poing un trou dans sa fenêtre, de sorte que la superposition est visible. Puis, il le garde en synchronisation avec la mise en page (par exemple. si vous déplacez ou redimensionnez VideoView, la superposition doit être déplacée et redimensionnée).
Il y a un bug quelque part au cours de la mise en page de phase qui fait de la superposition de la taille définie par VideoView.
De le fixer, sous-classe VideoView et remplacer onLayout:
et la superposition va avoir la bonne taille de VideoView mise en page de l'dimensions.
De la réplication de l'application YouTube
J'ai réussi à construire un exemple de projet qui ne nécessite pas de
android:configChanges="orientation"
ou personnaliséVideoView
. L'expérience ainsi acquise est identique à la manière dont l'application YouTube poignées de rotation au cours de la lecture de la vidéo. En d'autres termes, la vidéo ne pas besoin de pause, re-mise en mémoire tampon, ou rechargés, et ne pas sauter ou tomber des trames audio lorsque l'appareil changements d'orientation.Méthode Optimale
Cette méthode utilise un TextureView et son accompagnement
SurfaceTexture
comme un puits pour laMediaPlayer
s'image vidéo en cours. Depuis un SurfaceTexture utilise un GL texture de l'objet (simplement référencé par un nombre entier à partir de la GL contexte), estiment qu'il est bon de conserver une référence à un SurfaceTexture par le biais de modifications de la configuration. Le TextureView lui-même est détruit et recréé lors de la modification de la configuration (avec le soutien de l'Activité), et le nouvellement créé TextureView est tout simplement mis à jour avec les SurfaceTexture de référence avant d'être fixé.J'ai créé un plein d'exemple montrant comment et quand pour initialiser votre lecteur multimédia et un possible MediaController, et je vais mettre en évidence les parties intéressantes pertinente à cette question ci-dessous:
Depuis la solution utilise une retenue de Fragment plutôt que d'une Activité qui gère les modifications de configuration manuellement, vous pouvez tirer pleinement parti de la configuration spécifique des ressources de l'inflation système comme vous le feriez naturellement. Malheureusement, si votre minimum sdk est au-dessous de l'API de 16, vous aurez essentiellement besoin de rétroporter
TextureView
(que je n'ai pas fait).Enfin, si vous êtes intéressé, checkout ma question de départ détaillant: mon approche originale, le média Android pile, pourquoi il n'a pas de travail, et de l'autre une solution de contournement.
TextureView.setSurfaceTexture()
.utiliser ceci :
Aussi ne pas oublier d'ajouter la ligne ci-dessous pour votre Activité dans le Manifeste:
J'ai pris des exemples de certaines des réponses ici et a essayé de le faire à ma façon. Ressemble à une solution de facilité.
onConfigurationChange à l'intérieur d'un fragment.Où la vidéo est affichée en plein écran en mode paysage.Notez que je suis le masquage de la barre d'action.
et voici mon fichier de mise en page
J'ai une autre relativelayout en dessous de ce qui n'est pas dans cette disposition. Mais que ne ferait aucune différence.
voir mon exemple de code, ça marche pour moi
et ne pas re-créer la vue lorsque le changement d'orientation
paysage
mon code source
Tout Mark37 (très utile) réponse fonctionne, il faut définir les dimensions manuellement (à l'aide de setDimensions). Cela peut-être bien dans une application où les dimensions sont connues à l'avance, mais si vous voulez le point de vue de déterminer la taille automatiquement en fonction de la vidéo de paramètres (par exemple, assurez-vous que le ratio d'aspect original est conservé), une approche différente est nécessaire.
Heureusement, il s'avère que la setDimensions partie n'est pas réellement nécessaire. VideoView de onMeasure comprend déjà toute la logique nécessaire, de sorte qu'au lieu de compter sur quelqu'un pour appeler setDimensions, il est possible de simplement appeler super.onMeasure, puis utiliser la vue du getMeasuredWidth/getMeasuredHeight pour obtenir la taille fixe.
Donc, le VideoViewCustom classe devient simplement:
Cette version ne nécessite pas de code supplémentaire dans l'appelant, et profite pleinement de VideoView existant onMeasure mise en œuvre.
C'est en fait assez similaire à celui de la approche suggéré par Zapek, qui fait la même chose, seulement avec onLayout au lieu de onMeasure.
Réponse SIMPLE et jusqu'à la date de 2018.
Points positifs pour cette réponse: Code est ci-dessous
1) Il n'a pas d'importance si vous définissez à FULL_SCREEN ou pas. Comme il correspondre à la mère, il le sera toujours. Dans l'ancien accepté de répondre si vous n'avez pas configuré pour FULL_SCREEN, android va prendre l'ensemble de la taille de téléphone, puis les VideoView sera à l'extérieur de l'écran;
2) Vous n'avez pas besoin de créer un Personnalisé VideoView ou PlayerView;
3) Il n'appelle pas la méthode à plusieurs reprises. Dans l'ancien accepté de répondre, il appelle onMeasure plusieurs fois inutile;
4) Il ya aussi un bouton pour modifier l'orientation comme youtube app;
5) Réglage du téléphone rotation auto sur OFF aussi bloquer l'application de l'orientation du changement.
OBS: je suis en utilisant PlayerView à l'intérieur d'un ConstraintLayout. Parce que je travaille avec ExoPlayer Bibliothèque De Médias.
fragment_player.xml
SUPPLÉMENTAIRES
Je veux aussi un bouton pour changer l'orientation
De reproduire entièrement application youtube, vous aurez probablement envie d'un bouton pour régler le joueur en paysage ou en portrait, c'est utile si l'utilisateur est avec le téléphone de la rotation automatique de l'arrêt.
Tout d'abord, vous devez suivre ces étapes:
PlayerFragment.java
PROBLÈME 1: la Rotation de l'appareil ne fonctionne plus
Vous remarquerez que si vous cliquez sur le bouton pour changer l'orientation, la rotation de l'appareil ne fonctionnera plus pour changer la taille du lecteur. Cela se produit parce que vous définissez l'orientation Paysage ou Portrait par programme et il restera comme ça pour toujours, donc vous avez besoin d'un moyen de définir l'orientation du CAPTEUR, de sorte que lorsque vous faites pivoter l'appareil lui permet de vérifier quelle est la véritable orientation. La méthode ci-dessous le fera pour vous.
PROBLÈME 2: le Téléphone de la rotation automatique est DÉSACTIVÉ et il a encore un changement d'orientation
À l'intérieur de la méthode ci-dessous, vous devez vérifier si le téléphone de la rotation automatique est activé ou DÉSACTIVÉ, dans le cas où c'est SUR, vous pouvez définir l'ORIENTATION du CAPTEUR, de sorte que le téléphone sera en mesure de changer d'orientation lorsque l'utilisateur de faire pivoter l'appareil. En cas de rotation automatique est DÉSACTIVÉE, vous ne faites rien, de sorte que l'orientation sera bloquer en mode Portrait ou en Paysage, en fonction de si l'utilisateur a appuyé sur le bouton plein écran ou pas.
Si vous travaillez avec une application multimédia, j'ai un exemple qui vous guideront sur la façon d'utiliser puissamment Exoplayer Bibliothèque.
J'ai essayé d'utiliser le code d'autres réponses, mais elle ne résout pas mon problème, parce que si je fait tourner rapidement l'écran, ma taille de la vidéo a été frappé. J'ai donc utiliser une partie de leur code, que j'ai mis dans un thread qui met à jour la fenêtre très rapidement.
Donc, voici mon code:
De cette façon, la taille de la vidéo sera toujours à droite (dans mon cas).