Android让VideoView填充满屏幕/父布局并保证不变形

在Android中简单的播放一下视频选用VideoView是一个不错的选择,各个厂商在出厂的时候一般都会测试视频播放,这个兼容性一般都能得到保证,而且使用VideoView播放会自动的纠正视频角度,但是有一个问题VideoView在使用过程中总是有一些空白区域留出来,很多时候我们想让他填充满屏幕,或者说父布局,于是就有了今天的议题(当然也可以通过OpenGL来自己画视频,想显示成什么样子就显示成什么样子,只不过这个相对来说麻烦一点)。

​ 首先VideoView在使用的时候有一个坑,就是在初始化的时候一定要把视频地址给到它,否则视频是变形的,因为在布局的时候没有拿到视频的尺寸信息,所以初始化的时候并不知道要初始化多大的Surface,这就决定了VideoView的两种使用方式:

  1. 在xml里面放置的时候,那么在Activity onCreate的时候就需要把视频地址传进去。
  2. 动态的new VideoView()然后添加到指定的父控件里面,同时也需要把视频地址传进去

原理如下:

  1. 拿到视频地址后取出准确的视频宽高
  2. 在onSizeChanged的时候根据视频宽高和父布局的宽高来计算出VideoView的布局参数,把视频多出来的区域通过-margin来让它显示到控件外面去,进而达到填充满父控件的目的
  3. 重写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;
    }
}

Demo工程地址:https://github.com/bookzhan/FillParentVideoView

此条目发表在Android分类目录。将固定链接加入收藏夹。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注