如何在RecyclerView的onBindViewHolder中设置VideoView高度为200dp?
我之前也踩过这个坑!RecyclerView里的VideoView因为自身的测量逻辑和列表项复用的特性,直接用setLayoutParams()或者XML设高度经常会被覆盖,给你几个亲测有效的方案:
方案1:给VideoView套一层父容器(最简单直接)
VideoView会默认根据视频的宽高比自动调整自身大小,直接给它设高度很容易被这个逻辑冲掉。解决思路是用一个容器把它包起来,固定容器的高度,再让VideoView填充满容器,通过scaleType控制视频的拉伸/压缩方式。
示例XML布局
<!-- 父容器固定200dp高度 --> <FrameLayout android:id="@+id/video_container" android:layout_width="match_parent" android:layout_height="200dp"> <VideoView android:id="@+id/video_view" android:layout_width="match_parent" android:layout_height="match_parent" android:scaleType="centerCrop" /> <!-- scaleType可选值: fitXY = 强制拉伸填满容器 centerCrop = 保持比例裁剪填充满 fitCenter = 保持比例居中显示(会留黑边) --> </FrameLayout>
代码中动态调整(如果需要)
如果要在onBindViewHolder里动态改高度,直接给父容器设置参数就行:
FrameLayout videoContainer = holder.itemView.findViewById(R.id.video_container); ViewGroup.LayoutParams params = videoContainer.getLayoutParams(); // 把200dp转成像素值,也可以提前在dimens.xml里定义 params.height = getResources().getDimensionPixelSize(R.dimen.video_height_200dp); videoContainer.setLayoutParams(params);
方案2:自定义VideoView,重写测量逻辑
如果不想套容器,可以自定义一个VideoView,强制它使用我们指定的高度,忽略视频的默认比例约束。
自定义View代码
public class FixedHeightVideoView extends VideoView { private int mFixedHeight; public FixedHeightVideoView(Context context) { super(context); } public FixedHeightVideoView(Context context, AttributeSet attrs) { super(context, attrs); // 支持从XML属性读取固定高度 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FixedHeightVideoView); mFixedHeight = a.getDimensionPixelSize(R.styleable.FixedHeightVideoView_fixedHeight, 0); a.recycle(); } // 提供动态设置高度的方法 public void setFixedHeight(int height) { mFixedHeight = height; requestLayout(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (mFixedHeight > 0) { // 强制使用我们指定的高度,宽度跟随父布局 heightMeasureSpec = MeasureSpec.makeMeasureSpec(mFixedHeight, MeasureSpec.EXACTLY); } super.onMeasure(widthMeasureSpec, heightMeasureSpec); } }
使用方式
在XML里直接用自定义View:
<com.yourpackage.FixedHeightVideoView android:id="@+id/video_view" android:layout_width="match_parent" android:layout_height="200dp" app:fixedHeight="200dp" />
或者在onBindViewHolder里动态设置:
FixedHeightVideoView videoView = holder.itemView.findViewById(R.id.video_view); int fixedHeight = getResources().getDimensionPixelSize(R.dimen.video_height_200dp); videoView.setFixedHeight(fixedHeight); videoView.setVideoPath(yourVideoUrl);
方案3:用TextureView替代VideoView(最灵活)
VideoView的底层是TextureView,但它的封装太死,不如直接用TextureView配合MediaPlayer来控制,完全掌握尺寸的主动权。
示例布局
<TextureView android:id="@+id/texture_view" android:layout_width="match_parent" android:layout_height="200dp" />
代码实现(关键部分)
// 在onBindViewHolder里初始化播放逻辑 TextureView textureView = holder.itemView.findViewById(R.id.texture_view); MediaPlayer mediaPlayer = new MediaPlayer(); try { mediaPlayer.setDataSource(yourVideoUrl); mediaPlayer.setSurface(new Surface(textureView.getSurfaceTexture())); mediaPlayer.prepareAsync(); mediaPlayer.setOnPreparedListener(mp -> { mp.start(); // 还可以在这里通过矩阵调整视频的显示比例,比如拉伸、裁剪 }); } catch (IOException e) { e.printStackTrace(); } // 重要!在列表项复用时释放资源,避免内存泄漏 @Override public void onViewRecycled(@NonNull ViewHolder holder) { super.onViewRecycled(holder); if (holder.mediaPlayer != null) { holder.mediaPlayer.stop(); holder.mediaPlayer.release(); holder.mediaPlayer = null; } }
注意事项
不管用哪种方案,都要处理RecyclerView的复用问题:在onViewRecycled或者onBindViewHolder里重置视频的状态(停止播放、释放资源),不然复用的时候会出现视频串流、卡顿甚至崩溃的情况。
内容的提问来源于stack exchange,提问作者Arpit Gupta
相关产品推荐
相关产品推荐

