在Android中简单的播放一下视频选用VideoView是一个不错的选择,各个厂商在出厂的时候一般都会测试视频播放,这个兼容性一般都能得到保证,而且使用VideoView播放会自动的纠正视频角度,但是有一个问题VideoView在使用过程中总是有一些空白区域留出来,很多时候我们想让他填充满屏幕,或者说父布局,于是就有了今天的议题(当然也可以通过OpenGL来自己画视频,想显示成什么样子就显示成什么样子,只不过这个相对来说麻烦一点)。
首先VideoView在使用的时候有一个坑,就是在初始化的时候一定要把视频地址给到它,否则视频是变形的,因为在布局的时候没有拿到视频的尺寸信息,所以初始化的时候并不知道要初始化多大的Surface,这就决定了VideoView的两种使用方式:
- 在xml里面放置的时候,那么在Activity onCreate的时候就需要把视频地址传进去。
- 动态的new VideoView()然后添加到指定的父控件里面,同时也需要把视频地址传进去
原理如下:
- 拿到视频地址后取出准确的视频宽高
- 在onSizeChanged的时候根据视频宽高和父布局的宽高来计算出VideoView的布局参数,把视频多出来的区域通过-margin来让它显示到控件外面去,进而达到填充满父控件的目的
- 重写onMeasure方法覆盖掉VideoView的逻辑,然后尽情享受吧
完整代码如下:
package bz.luoye.fillparentvideoview;
import android.content.Context;
import android.media.MediaMetadataRetriever;
import android.util.AttributeSet;
import android.util.Log;
import android.view.ViewGroup;
import android.widget.VideoView;
/**
* Created by zhandalin on 2020-06-05 09:13.
* description:
*/
public class FillParentVideoView extends VideoView {
private static final String TAG = "FillParentVideoView";
private int videoWidth = 0;
private int videoHeight = 0;
private int videoRotation = 0;
private boolean fullParentView = true;
public FillParentVideoView(Context context) {
this(context, null);
}
public FillParentVideoView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FillParentVideoView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
if (videoWidth > 0 && videoHeight > 0 && fullParentView) {
ViewGroup parent = (ViewGroup) getParent();
w = parent.getWidth();
h = parent.getHeight();
Log.d(TAG, "onSizeChanged w=" + w + " h=" + h);
float videoRatio = videoWidth * 1.0f / videoHeight;
float viewRatio = w * 1.0f / h;
ViewGroup.LayoutParams layoutParams = getLayoutParams();
if (viewRatio > videoRatio) {
layoutParams.width = w;
layoutParams.height = (int) (w / videoRatio + 0.5f);
} else {
layoutParams.width = (int) (h * videoRatio + 0.5f);
layoutParams.height = h;
}
if (layoutParams instanceof ViewGroup.MarginLayoutParams) {
ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) layoutParams;
if (layoutParams.width != w) {
marginLayoutParams.leftMargin = (w - layoutParams.width) / 2;
marginLayoutParams.rightMargin = (w - layoutParams.width) / 2;
}
if (layoutParams.height != h) {
marginLayoutParams.topMargin = (h - layoutParams.height) / 2;
marginLayoutParams.bottomMargin = (h - layoutParams.height) / 2;
}
Log.d(TAG, "leftMargin=" + marginLayoutParams.leftMargin + " rightMargin=" + marginLayoutParams.rightMargin + " topMargin=" + marginLayoutParams.topMargin + " bottomMargin=" + marginLayoutParams.bottomMargin);
}
setLayoutParams(layoutParams);
Log.d(TAG, "layoutParams width=" + layoutParams.width + " height=" + layoutParams.height);
}
super.onSizeChanged(w, h, oldw, oldh);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
Log.d(TAG, "onLayout " + changed + " left=" + left + " top=" + top + " right=" + right + " bottom=" + bottom);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (fullParentView) {
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
@Override
public void setVideoPath(String path) {
try {
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setDataSource(path);
String widthString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
String heightString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
String rotationString = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
Log.d(TAG, "video width=" + widthString + " height=" + heightString + " rotation=" + rotationString);
videoWidth = Integer.parseInt(widthString);
videoHeight = Integer.parseInt(heightString);
int tempRotation = Integer.parseInt(rotationString);
videoRotation = (tempRotation % 360 + 360) % 360;
if (videoRotation == 90 || videoRotation == 270) {
int temp = videoWidth;
videoWidth = videoHeight;
videoHeight = temp;
}
Log.d(TAG, "videoRotation=" + videoRotation + " videoWidth=" + videoWidth + " videoHeight=" + videoHeight);
} catch (Exception e) {
e.printStackTrace();
}
super.setVideoPath(path);
ViewGroup.LayoutParams layoutParams = getLayoutParams();
setLayoutParams(layoutParams);
}
public boolean isFullParentView() {
return fullParentView;
}
public void setFullParentView(boolean fullParentView) {
this.fullParentView = fullParentView;
}
public int getVideoWidth() {
return videoWidth;
}
public void setVideoWidth(int videoWidth) {
this.videoWidth = videoWidth;
}
public int getVideoHeight() {
return videoHeight;
}
public void setVideoHeight(int videoHeight) {
this.videoHeight = videoHeight;
}
public int getVideoRotation() {
return videoRotation;
}
public void setVideoRotation(int videoRotation) {
this.videoRotation = videoRotation;
}
}