Android VideoView orientation change with buffered video
Solution 1:
EDIT: (June 2016)
This answer is very old (I think android 2.2/2.3) and probably is not as relevant as the other answers below! Look to them first unless you're dev-ing on legacy Android :)
I was able to narrow down the problem to the onMeasure function in the VideoView class. By creating a child class and overriding the onMeasure function, I was able to get the desired functionality.
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);
}
}
Then inside my Activity I just did the following:
@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);
}
}
The line:
questionVideo.getHolder().setFixedSize(displayWidth, smallHeight);
is key in order to make this work. If you do the setDimensions call without this guy, the video still will not resize.
The only other thing you need to do is ensure that you call setDimensions() inside the onCreate() method as well or your video will not start buffering as the video won't be set to draw on a surface of any size.
// onCreate()
questionVideo.setDimensions(initialWidth, initialHeight);
One last key part - if you ever find yourself wondering why the VideoView isn't resizing on rotation, you need to ensure the dimensions you're resizing to are either exactly equal to the visible area or less than it. I had a really big problem where I was setting the VideoView's width/height to the entire display size when I still had the notification bar/title bar on the screen and it was not resizing the VideoView at all. Simply removing the notification bar and title bar fixed the problem.
Hopefully this helps someone in the future!
Solution 2:
Here is a really easy way to accomplish what you want with minimal code:
AndroidManifest.xml:
android:configChanges="orientation|keyboard|keyboardHidden|screenSize|screenLayout|uiMode"
Note: Edit as needed for your API, this covers 10+, but lower APIs require removing the "screenSize|screenLayout|uiMode" portion of this line
Inside the "OnCreate" method, usually under "super.onCreate", add:
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
And then somewhere, usually at the bottom, add:
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
}
This will resize the video to fullscreen whenever the orientation has changed without interrupting playback and only requires overriding the configuration method.
Solution 3:
First of all, thanks a lot for your own extensive answer.
I had the same problem, the video would most of the time be smaller, or bigger, or distorted inside the VideoView after a rotation.
I tried your solution, but I also tried random things, and by chance I noticed that if my VideoView is centered in its parent, it magically works by itself (no custom VideoView needed or anything).
To be more specific, with this layout, I reproduce the problem most of the time:
<?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>
With this one layout, I never have the problem (plus, the video is centered, which is how it should be anyway ;):
<?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>
It also works with wrap_content
instead of match_parent
(the video still takes all the space) which does not make much sense to me.
Anyway, I don't have any explanation for this - this looks like a VideoView bug to me.
Solution 4:
VideoView uses what's called an overlay which is an area where the video is rendered. That overlay is behind the window holding the VideoView. VideoView punches a hole in its window so that the overlay is visible. It then keeps it in sync with the layout (eg. if you move or resize VideoView, the overlay has to be moved and resized as well).
There's a bug somewhere during the layout phase which makes the overlay use the previous size set by VideoView.
To fix it, subclass VideoView and override onLayout:
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
getHolder().setSizeFromLayout();
}
and the overlay will have the correct size from VideoView's layout dimensions.