Mar*_* G. 50 android android-orientation 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));
}
}
Run Code Online (Sandbox Code Playgroud)
编辑:我在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
Run Code Online (Sandbox Code Playgroud)
调整大小时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
Run Code Online (Sandbox Code Playgroud)
也许有人知道'Overlay'是什么以及为什么它没有得到正确的身高值?
Mar*_* G. 57
编辑:( 2016年6月)
这个答案非常陈旧(我认为android 2.2/2.3)并且可能与下面的其他答案没有相关性!首先看看他们,除非你正在开发传统的Android :)
我能够将问题缩小到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);
}
}
Run Code Online (Sandbox Code Playgroud)
然后在我的活动中,我刚刚做了以下事情:
@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);
}
}
Run Code Online (Sandbox Code Playgroud)
这条线:
questionVideo.getHolder().setFixedSize(displayWidth, smallHeight);
Run Code Online (Sandbox Code Playgroud)
是这项工作的关键.如果你在没有这个人的情况下进行setDimensions调用,视频仍然不会调整大小.
您需要做的唯一其他事情是确保您在onCreate()方法中调用setDimensions()或者您的视频不会开始缓冲,因为视频不会设置为在任何大小的表面上绘制.
// onCreate()
questionVideo.setDimensions(initialWidth, initialHeight);
Run Code Online (Sandbox Code Playgroud)
最后一个关键部分 - 如果您发现自己想知道为什么VideoView没有在旋转时调整大小,您需要确保要调整大小的尺寸要么与可见区域完全相等,要么小于它.我有一个非常大的问题,当我在屏幕上仍然有通知栏/标题栏并且根本没有调整VideoView的大小时,我将VideoView的宽度/高度设置为整个显示大小.只需删除通知栏和标题栏即可解决问题.
希望这有助于未来的人!
BoD*_*BoD 23
首先,非常感谢您自己的广泛答案.
我遇到了同样的问题,旋转后视频大部分时间内视频会变小或变大或变形.
我尝试了你的解决方案,但我也尝试过随机的东西,我偶然发现如果我的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>
Run Code Online (Sandbox Code Playgroud)
有了这个布局,我从来没有遇到过这个问题(另外,视频是居中的,无论如何都应该如此;):
<?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>
Run Code Online (Sandbox Code Playgroud)
它也适用wrap_content而不是match_parent(视频仍占用所有空间)对我来说没有多大意义.
无论如何,我对此没有任何解释 - 这对我来说看起来像一个VideoView错误.
Aba*_*art 23
这是一个用最少的代码完成你想要的东西的简单方法:
AndroidManifest.xml中:
android:configChanges="orientation|keyboard|keyboardHidden|screenSize|screenLayout|uiMode"
Run Code Online (Sandbox Code Playgroud)
注意:根据API的需要进行编辑,这包括10+,但是较低的API需要删除此行的"screenSize | screenLayout | uiMode"部分
在"OnCreate"方法中,通常在"super.onCreate"下,添加:
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
Run Code Online (Sandbox Code Playgroud)
然后在某处,通常在底部,添加:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
Run Code Online (Sandbox Code Playgroud)
只要方向发生变化而不中断播放,这将调整视频大小全屏,只需要覆盖配置方法.
小智 11
VideoView使用所谓的覆盖,即覆盖视频的区域.该叠加层位于持有VideoView的窗口后面.VideoView在其窗口中打出一个洞,以便可以看到叠加层.然后它使其与布局保持同步(例如,如果移动或调整VideoView的大小,则必须移动叠加层并调整其大小).
在布局阶段某处存在一个错误,使得叠加层使用VideoView设置的先前大小.
要修复它,请继承VideoView并覆盖onLayout:
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
getHolder().setSizeFromLayout();
}
Run Code Online (Sandbox Code Playgroud)
并且叠加层将具有VideoView布局尺寸的正确尺寸.
我设法构建了一个不需要 android:configChanges="orientation"或自定义的示例项目VideoView.由此产生的体验与YouTube应用在视频播放过程中处理轮换的方式相同.换句话说,视频不需要暂停,重新缓冲或重新加载,并且在设备方向改变时不会跳过或丢弃任何音频帧.
此方法使用TextureView及其附带SurfaceTexture作为MediaPlayer当前视频帧的接收器.由于SurfaceTexture使用GL纹理对象(简单地通过GL上下文中的整数引用),因此相信通过配置更改保留对SurfaceTexture的引用是可以的.在配置更改期间(以及后备Activity),TextureView本身将被销毁并重新创建,并且在连接之前,只需使用SurfaceTexture引用更新新创建的TextureView.
我已经创建了一个完整的工作示例,显示了如何以及何时初始化MediaPlayer和可能的MediaController,我将在下面突出显示与此问题相关的有趣部分:
public class VideoFragment {
TextureView mDisplay;
SurfaceTexture mTexture;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View rootView = inflater.inflate(R.layout.fragment_main, container, false);
mDisplay = (TextureView) rootView.findViewById(R.id.texture_view);
if (mTexture != null) {
mDisplay.setSurfaceTexture(mTexture);
}
mDisplay.setSurfaceTextureListener(mTextureListener);
return rootView;
}
TextureView.SurfaceTextureListener mTextureListener = new TextureView.SurfaceTextureListener() {
@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
mTexture = surface;
// Initialize your media now or flag that the SurfaceTexture is available..
}
@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
mTexture = surface;
}
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
mTexture = surface;
return false; // this says you are still using the SurfaceTexture..
}
@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
mTexture = surface;
}
};
@Override
public void onDestroyView() {
mDisplay = null;
super.onDestroyView();
}
// ...
}
Run Code Online (Sandbox Code Playgroud)
由于解决方案使用保留的Fragment而不是手动处理配置更改的Activity,因此您可以自然地充分利用特定于配置的资源膨胀系统.不幸的是,如果你的最低sdk低于API 16,你基本上需要backport TextureView(我还没有).
最后,如果您有兴趣,请查看我的初步问题详细说明:我的原始方法,Android媒体堆栈,它为什么不起作用,以及替代解决方法.
| 归档时间: |
|
| 查看次数: |
55903 次 |
| 最近记录: |