如何将VideoView转为圆形?及实现全屏播放后裁剪为圆形的方法
嘿,这两个关于VideoView的问题我刚好在项目里处理过,给你分享下靠谱的实现方案:
问题1:如何将VideoView转换为圆形?
VideoView本身是矩形控件,没法直接改成圆形,我们得通过画布裁剪或者遮罩层的方式来实现,下面是两种常用的可靠方案:
方案一:自定义容器裁剪(兼容全版本)
创建一个自定义的FrameLayout子类,在绘制时裁剪画布为圆形,把VideoView放在这个容器里就行:
public class CircleVideoContainer extends FrameLayout { private Path mCirclePath; private RectF mCircleRect; private boolean mIsCircle = true; // 控制是否裁剪为圆形 public CircleVideoContainer(Context context) { super(context); init(); } public CircleVideoContainer(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { mCirclePath = new Path(); mCircleRect = new RectF(); setWillNotDraw(false); // 必须开启,否则onDraw不会执行 } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); // 取宽高中的最小值做直径,保证是正圆 int diameter = Math.min(w, h); mCircleRect.set( (w - diameter) / 2, (h - diameter) / 2, (w + diameter) / 2, (h + diameter) / 2 ); mCirclePath.addOval(mCircleRect, Path.Direction.CW); } @Override protected void onDraw(Canvas canvas) { if (mIsCircle) { canvas.clipPath(mCirclePath); // 裁剪出圆形区域 } super.onDraw(canvas); } // 提供开关方法,方便后续动态切换 public void setCircleMode(boolean isCircle) { mIsCircle = isCircle; invalidate(); } }
然后在布局里这样用:
<com.yourpackage.CircleVideoContainer android:id="@+id/video_container" android:layout_width="250dp" android:layout_height="250dp" android:layout_gravity="center"> <VideoView android:id="@+id/video_view" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center"/> </com.yourpackage.CircleVideoContainer>
方案二:遮罩层实现(API 16+)
给VideoView设置一个圆形的遮罩层,通过PorterDuff混合模式只显示圆内的内容:
// 创建圆形遮罩 ShapeDrawable circleMask = new ShapeDrawable(new OvalShape()); circleMask.getPaint().setColor(Color.BLACK); // 用DST_IN模式,只保留遮罩覆盖的区域 circleMask.getPaint().setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); // 给VideoView设置遮罩 videoView.setForeground(circleMask);
如果是API 23以上,还可以更简单:
- 新建一个圆形的drawable文件
circle_background.xml:
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <solid android:color="@android:color/transparent"/> </shape>
- 给VideoView设置背景并开启裁剪:
videoView.setBackgroundResource(R.drawable.circle_background); videoView.setClipToOutline(true);
注意:不管哪种方案,都要保证VideoView的宽高一致,否则会变成椭圆;如果需要兼容低版本,优先用自定义容器的方案。
问题2:全屏播放后一段时间裁剪为圆形
这个需求需要分两步实现:先全屏播放,延迟指定时间后切换为圆形显示,结合上面的自定义容器方案,具体步骤如下:
1. 实现全屏播放逻辑
private void enterFullscreen() { // 隐藏状态栏和导航栏 getWindow().setFlags( WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN ); // 隐藏ActionBar(如果有的话) if (getSupportActionBar() != null) { getSupportActionBar().hide(); } // 把VideoView设置为全屏尺寸 ViewGroup.LayoutParams params = mVideoView.getLayoutParams(); params.width = ViewGroup.LayoutParams.MATCH_PARENT; params.height = ViewGroup.LayoutParams.MATCH_PARENT; mVideoView.setLayoutParams(params); // 关闭容器的圆形裁剪(初始状态全屏不裁剪) mVideoContainer.setCircleMode(false); }
2. 延迟切换为圆形显示
用Handler来实现延迟任务,比如延迟5秒后切换:
private void startDelayToCircleMode() { new Handler(Looper.getMainLooper()).postDelayed(() -> { // 切换为圆形模式 mVideoContainer.setCircleMode(true); // 调整VideoView的尺寸为圆形大小(比如250dp) int circleSize = getResources().getDimensionPixelSize(R.dimen.circle_video_size); ViewGroup.LayoutParams params = mVideoView.getLayoutParams(); params.width = circleSize; params.height = circleSize; params.gravity = Gravity.CENTER; // 居中显示 mVideoView.setLayoutParams(params); // 恢复状态栏和ActionBar(可选,根据需求调整) getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); if (getSupportActionBar() != null) { getSupportActionBar().show(); } }, 5000); // 5秒延迟,可根据需求修改时间 }
3. 调用流程
在播放视频的时候,先调用全屏方法,再启动延迟任务:
// 初始化VideoView并设置视频路径 mVideoView.setVideoURI(Uri.parse("your_video_path")); mVideoView.start(); // 进入全屏播放 enterFullscreen(); // 启动延迟切换任务 startDelayToCircleMode();
小提示:如果担心内存泄漏,可以用
View.postDelayed()或者Coroutines代替Handler,效果是一样的。
内容的提问来源于stack exchange,提问作者kaustav07
相关产品推荐
相关产品推荐

