使用缓冲视频更改Android VideoView方向

我试图从本质上复制Android市场上最新的YouTube应用的功能。 观看视频时,有两种独立的布局,一种是纵向显示附加信息,另一种是横向显示,可以全屏显示视频。

YouTube应用程序肖像布局
YouTupe应用程序在肖像模式

YouTube应用横向布局
横向模式下的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

下一篇: Android VideoView resume and seekTo