使用缓冲视频更改Android VideoView方向
我试图从本质上复制Android市场上最新的YouTube应用的功能。 观看视频时,有两种独立的布局,一种是纵向显示附加信息,另一种是横向显示,可以全屏显示视频。
YouTupe应用程序在肖像模式
横向模式下的YouTube应用
(抱歉照片的随机性,但它们是我能找到的实际布局的第一张照片)
这通常很容易实现 - 只需在layout-land中指定一个备用布局,并且所有内容都会很好。 YouTube应用程序确实做得很好(以及我想要复制的内容)是,在方向更改时,视频会继续播放,并且不必从头开始重新缓冲。
我已经知道重写onConfigurationChange()并设置新的LayoutParameters将允许我调整视频的大小而不强制重新播放 - 但是当多次旋转屏幕时,视频会随机缩放到不同的宽度/高度。 我试过对VideoView进行各种invalidate()调用,试图在父亲RelativeLayout容器上调用RequestLayout(),尽可能尝试尽可能多的东西,但我似乎无法让它正常工作。 任何建议将不胜感激!
这是我的代码:
@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));
}
}
编辑:我发现logcat一些有趣的输出,当我的视频旋转似乎是罪魁祸首 - 虽然我不知道如何解决它:
正确调整大小时的Logcat输出(占用整个窗口)
注意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输出(占用全屏幕的一小部分)
注意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
也许有人知道'Overlay'是什么,为什么它没有得到正确的身高值?
我能够将问题缩小到VideoView类中的onMeasure函数。 通过创建子类并覆盖onMeasure函数,我能够获得所需的功能。
public class VideoViewCustom extends VideoView {
private int mForceHeight = 0;
private int mForceWidth = 0;
public VideoViewCustom(Context context) {
super(context);
}
public VideoViewCustom(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public VideoViewCustom(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void setDimensions(int w, int h) {
this.mForceHeight = h;
this.mForceWidth = w;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Log.i("@@@@", "onMeasure");
setMeasuredDimension(mForceWidth, mForceHeight);
}
}
然后在我的活动中,我做了以下操作:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
questionVideo.setDimensions(displayHeight, displayWidth);
questionVideo.getHolder().setFixedSize(displayHeight, displayWidth);
} else {
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN, WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
questionVideo.setDimensions(displayWidth, smallHeight);
questionVideo.getHolder().setFixedSize(displayWidth, smallHeight);
}
}
该行:
questionVideo.getHolder().setFixedSize(displayWidth, smallHeight);
是做这项工作的关键。 如果你没有这个人做setDimensions调用,视频仍然不会调整大小。
您唯一需要做的另一件事是确保您在onCreate()方法中调用setDimensions(),否则视频将不会开始缓冲,因为视频不会设置为在任何大小的表面上绘制。
// onCreate()
questionVideo.setDimensions(initialWidth, initialHeight);
最后一个关键部分-如果你发现自己想知道为什么VideoView没有在旋转调整,你需要确保你调整大小或者是正好等于可视面积或低于它的尺寸。 当我仍然在屏幕上显示通知栏/标题栏并且根本没有调整VideoView的大小时,我遇到了一个非常大的问题,即将VideoView的宽度/高度设置为整个显示大小。 只需删除通知栏和标题栏即可解决问题。
希望这有助于未来的人!
编辑:( 2016年6月)
这个答案是非常古老的(我认为android 2.2 / 2.3),可能不如下面的其他答案相关! 先看看他们,除非你正在开发旧版Android :)
首先,非常感谢您的广泛答复。
我遇到了同样的问题,视频会在旋转后的大部分时间内变小,变大或变形。
我尝试了你的解决方案,但我也试过随机的东西,偶然我发现如果我的VideoView是在其父母中居中,它神奇地自行工作(没有自定义VideoView需要或任何东西)。
更具体地说,在这个布局中,我大多数时候都会重现这个问题:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<VideoView
android:id="@+id/videoView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
有了这个布局,我从来没有遇到过这个问题(再加上,视频是以中心为基础的,反正它应该如此;):
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<VideoView
android:id="@+id/videoView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true" />
</RelativeLayout>
它也适用于wrap_content
而不是match_parent
(视频仍占用所有空间),这对我来说没什么意义。
无论如何,我对此没有任何解释 - 这看起来像是一个VideoView bug。
这是一个非常简单的方法,用最少的代码完成你想要的任务:
AndroidManifest.xml中:
android:configChanges="orientation|keyboard|keyboardHidden|screenSize|screenLayout|uiMode"
注意:根据需要编辑您的API,这涵盖10+,但较低的API需要删除此行的“screenSize | screenLayout | uiMode”部分
在“OnCreate”方法中,通常在“super.onCreate”下添加:
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
然后通常在底部的某个地方添加:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
这会将视频调整为全屏,只要方向改变而不中断播放并且只需要重写配置方法即可。
链接地址: http://www.djcxy.com/p/46485.html上一篇: Android VideoView orientation change with buffered video