VideoView匹配父高度和保持宽高比(VideoView to match parent hei

2019-06-21 08:10发布

我有建立这样一个VideoView:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  android:id="@+id/player" 
  android:orientation="vertical"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent">

    <VideoView
        android:id="@+id/video"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_centerInParent="true"
        android:layout_centerVertical="true" />

    <ProgressBar
        android:id="@+id/loader"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true" />

</RelativeLayout>

但VideoView父容器的宽度相匹配,然后将高度根据被加载的影片的宽高比设置。
我想这样做正好相反,我希望VideoView,同时保持长宽比不变符合父母的高度,视频将在两侧被裁剪。

我设法拉伸VideoView以填充父但随后的纵横比不存。

另一件事是,我加入的MediaController像这样的VideoView:

MediaController controllers = new MediaController(this) {
    @Override
    public void hide() {
        if (state != State.Hidden) {
            this.show();
        }
        else {
            super.hide();
        }
    }
};
controllers.setAnchorView(videoView);
videoView.setMediaController(controllers);

videoView.setOnPreparedListener(new OnPreparedListener() {
    @Override
    public void onPrepared(MediaPlayer mediaPlayer) {
        controllers.show();
    }
});

这个伟大的工程,以及控制器永远留在,但控制器的高度计算时在何处放置视频(因为它是垂直居中)不被考虑。

我的两个问题,然后是:

  1. 如何让我的VideoView符合父母的高度但保持宽高比?
  2. 我如何让VideoView考虑到高度的它的控制器?

谢谢。

Answer 1:

您应该扩展内置的视频观看。

呼叫setVideoSize显示视频视图之前,你可以从视频中提取缩略图获取视频的大小。

所以,当视频视图的onMeasure被调用时,都mVideoWidthmVideoHeight是> 0。

如果你想占控制器的高度,你可以自己做的onMeasure方法。

希望会有所帮助。

public class MyVideoView extends VideoView {

        private int mVideoWidth;
        private int mVideoHeight;

        public MyVideoView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }

        public MyVideoView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
        }

        public MyVideoView(Context context) {
            super(context);
        }

        public void setVideoSize(int width, int height) {
            mVideoWidth = width;
            mVideoHeight = height;
        }

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            // Log.i("@@@", "onMeasure");
            int width = getDefaultSize(mVideoWidth, widthMeasureSpec);
            int height = getDefaultSize(mVideoHeight, heightMeasureSpec);
            if (mVideoWidth > 0 && mVideoHeight > 0) {
                if (mVideoWidth * height > width * mVideoHeight) {
                    // Log.i("@@@", "image too tall, correcting");
                    height = width * mVideoHeight / mVideoWidth;
                } else if (mVideoWidth * height < width * mVideoHeight) {
                    // Log.i("@@@", "image too wide, correcting");
                    width = height * mVideoWidth / mVideoHeight;
                } else {
                    // Log.i("@@@", "aspect ratio is correct: " +
                    // width+"/"+height+"="+
                    // mVideoWidth+"/"+mVideoHeight);
                }
            }
            // Log.i("@@@", "setting size: " + width + 'x' + height);
            setMeasuredDimension(width, height);
        }
}


Answer 2:

我解决了这个问题与布局。 看来,它工作得很好,当它被钉在角落,但它造成的视频歪斜。 为了测试我改变了我的相对布局的背景#990000看穿红戳。

<?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"
    android:id="@+id/relative_parent"
    android:background="#000000">
    <VideoView
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:focusable="false"
        android:focusableInTouchMode="false"
        android:id="@+id/videoView" />
</RelativeLayout>


Answer 3:

public class MyVideoView extends VideoView {
    private int mVideoWidth;
    private int mVideoHeight;

    public MyVideoView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyVideoView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public MyVideoView(Context context) {
        super(context);
    }


    @Override
    public void setVideoURI(Uri uri) {
        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
        retriever.setDataSource(this.getContext(), uri);
        mVideoWidth = Integer.parseInt(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH));
        mVideoHeight = Integer.parseInt(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT));
        super.setVideoURI(uri);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        // Log.i("@@@", "onMeasure");
        int width = getDefaultSize(mVideoWidth, widthMeasureSpec);
        int height = getDefaultSize(mVideoHeight, heightMeasureSpec);
        if (mVideoWidth > 0 && mVideoHeight > 0) {
            if (mVideoWidth * height > width * mVideoHeight) {
                // Log.i("@@@", "image too tall, correcting");
                height = width * mVideoHeight / mVideoWidth;
            } else if (mVideoWidth * height < width * mVideoHeight) {
                // Log.i("@@@", "image too wide, correcting");
                width = height * mVideoWidth / mVideoHeight;
            } else {
                // Log.i("@@@", "aspect ratio is correct: " +
                // width+"/"+height+"="+
                // mVideoWidth+"/"+mVideoHeight);
            }
        }
        // Log.i("@@@", "setting size: " + width + 'x' + height);
        setMeasuredDimension(width, height);
    }
}


Answer 4:

关于问题1,我很惊讶,没有人提到可能使用MediaPlayer的缩放模式进行。 https://developer.android.com/reference/android/media/MediaPlayer.html#setVideoScalingMode(int)

它有2种模式。 他们两人总是填充视图区域。 为了得到它,以填补空间,同时保持纵横比,从而裁剪长边,你需要切换到第二模式, VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING 。 解决该问题的一个组成部分。 另一部分是改变VideoView的测量行为,正如一些其他的答案证明。 这是我的方式做的,主要是出于懒惰和不熟悉的元数据API的,其他人使用,欢迎您使用此方法或其他方法来解决该视图的大小。 毯子捕捉确保安全时,这就是所谓的mMediaPlayer存在之前,因为它可以被称为很多次,也回落到原来的行为应该字段名曾经改变。

class FixedSizeVideoView : VideoView {
    constructor(ctx: Context) : super(ctx)
    constructor(ctx: Context, attrs: AttributeSet) : super(ctx, attrs)

    // rather than shrink down to fit, stay at the size requested by layout params. Let the scaling mode
    // of the media player shine through. If the scaling mode on the media player is set to the one
    // with cropping, you can make a player similar to AVLayerVideoGravityResizeAspectFill on iOS
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        try {
            val mpField = VideoView::class.java.getDeclaredField("mMediaPlayer")
            mpField.isAccessible = true
            val mediaPlayer: MediaPlayer = mpField.get(this) as MediaPlayer

            val width = View.getDefaultSize(mediaPlayer.videoWidth, widthMeasureSpec)
            val height = View.getDefaultSize(mediaPlayer.videoHeight, heightMeasureSpec)
            setMeasuredDimension(width, height)
        }
        catch (ex: Exception) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        }
    }
}

因此,使用这个类的布局,你只需要改变的缩放模式的媒体播放器上,无论你有机会。 如:

        video.setOnPreparedListener { mp: MediaPlayer ->
            mp.setVideoScalingMode(MediaPlayer.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING)
            mp.isLooping = true
            mp.setScreenOnWhilePlaying(false)
        }
        video.start()


Answer 5:

快速高效的解决办法:

无需创建VideoView延伸的自定义视图。 只需设置足够大的值android:layout_width 。 这将设置widthSpecMode视频视图的View.MeasureSpec.AT_MOST然后onMeasure() VideoView的方法将自动地调整其宽度保持率。

<VideoView
     android:id="@+id/video"
     android:layout_width="2000dp"
     android:layout_height="match_parent" />


Answer 6:

我花费在互联网上我没有找到任何更好的解决方案,可应用于默认视频视图上搜索这个时候。 所以,我搜索了这将解决我的要求库终于让我找到一个“FullscreenVideoView”( https://github.com/rtoshiro/FullscreenVideoView )这解决了我的要求,



Answer 7:

我已经尝试了很多解决方案,而我的视频在1000×1000格式始终,所以我创造了谁知道他们的纵横比人一个简单的解决方案。 首先建立在这样的一个RelativeLayout的VideoView:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:id="@+id/video_holder"
      android:layout_width="wrap_content"
      android:layout_height="fill_parent"
      android:clipToPadding="false">

      <VideoView  
          android:id="@+id/videoView"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:layout_alignParentBottom="true"
          android:layout_alignParentEnd="true"
          android:layout_alignParentStart="true"
          android:layout_alignParentTop="true" />
</RelativeLayout>

然后你之前加载视频改变高度和以编程这样的:

    int i = videoView.getHeight() > videoView.getWidth() ? videoView.getHeight() : videoView.getWidth();
    video_holder.setLayoutParams(new ConstraintLayout.LayoutParams(i, i));

当然,这仅适用于1:1个纵横比的,但你可以只用你的纵横比来改变高度或宽度。



Answer 8:

对于第一个时间的问题回答了我的问题,而不是答案! 我的问题是,我有充分的屏幕上的视频下一个空格。 我设置了layout_heightmatch_parent 。 解决的办法是将它设置为wrap_content ,给家长一个黑色的背景。 也就是说,和具有VideoView在其父垂直居中。

我写了这个作为一个评论,但随即想到有人可能有同样的问题我有,所以这里是作为一个答案也。



Answer 9:

Jobbert在科特林答案,万一有人需要它:

val max = if (videoView.height > videoView.width) videoView.height else videoView.width
videoView.layoutParams = ConstraintLayout.LayoutParams(max, max)


文章来源: VideoView to match parent height and keep aspect ratio