Android(安卓)Canvas清屏失效
16lz
2021-01-26
自定义控件时经常用到Canvas,画新的东西之前需要先清除画布内容,人脸识别项目中需要准确画出当前人脸位置,清空上一帧位置。
关于清除画布内容网上有两种非常流行的方法:
方法一:
mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
方法二: Paint paint = new Paint(); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); mCanvas.drawPaint(paint); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
遗憾的是这两种方法在我自定义的SurfaceView中都不起作用,尝试结果如出一辙,左右晃一下 画面如下: 我的解决方案是在每次设置Path画线前,清空一下Path,问题迎刃而解。
清除Path中的内容有两个方法:
reset( )不保留内部数据结构,但会保留FillType.
rewind( )会保留内部的数据结构,但不保留FillType
关于Path其他更多方法解释详见这篇博客。
自定义SurfaceView代码如下:
/** * Title: * Description: * Company: 北京****科技有限公司,010-62538800,[email protected] * * @author Created by ylwang on 2018/1/30 */public class CustomSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable { private SurfaceHolder mHolder; private Canvas mCanvas;//绘图的画布 private volatile boolean mIsDrawing;//控制绘画线程的标志位 private Paint mPaint; private Path mPath; public CustomSurfaceView(Context context) { super(context); initView(); } public CustomSurfaceView(Context context, AttributeSet attrs) { super(context, attrs); initView(); } public CustomSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(); } private Gson gson; private List listFaces; public void setFaceInfo(String faceInfo) { FaceBean bean = gson.fromJson(faceInfo, FaceBean.class); if (null != bean && null != bean.getFaces()) { listFaces = bean.getFaces(); } } private void initView() { mPaint = new Paint(); mPaint.setColor(Color.GREEN);//画笔颜色 mPaint.setAntiAlias(true);//抗锯齿 mPaint.setStrokeWidth(6);//画笔宽度 mPaint.setStyle(Paint.Style.STROKE);//空心 mPath = new Path(); mHolder = getHolder();//获取SurfaceHolder对象 //TODO:保证该SurfaceView在最上层,避免两个SurfaceView叠加,遮挡问题 mHolder.setFormat(PixelFormat.TRANSPARENT); setZOrderOnTop(true); mHolder.addCallback(this);//注册SurfaceHolder的回调方法 setFocusable(true);// 能否用键盘获得焦点 setFocusableInTouchMode(true);//能否通过触摸获得焦点 this.setKeepScreenOn(true);//屏幕常亮 gson = new Gson(); listFaces = new ArrayList<>(); } @Override public void surfaceCreated(SurfaceHolder holder) { mIsDrawing = true; new Thread(this).start(); } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } @Override public void surfaceDestroyed(SurfaceHolder holder) { mIsDrawing = false; } public static final int TIME_IN_FRAME = 20; @Override public void run() { long start; while (mIsDrawing) { start = SystemClock.uptimeMillis();//开始绘制 synchronized (this) { setPathToCanvas(); } //保证稳定帧率刷新界面 while (SystemClock.uptimeMillis() - start <= TIME_IN_FRAME) { Thread.yield();//线程让出 } } } private void setPathToCanvas() { mPath.rewind();//TODO:必须重置,否则不能清屏 //mPath.reset(); // mPath = new Path(); for (FaceBean.FacesEntity face : listFaces) { int[] ps = getPositions(face.getFace_rectangle()); mPath.moveTo(ps[0], ps[1]); for (int i = 2; i < ps.length - 1; i += 2) { mPath.lineTo(ps[i], ps[i + 1]); } mPath.close();//第一个点连接到最后一个点,形成一个闭合区域 //mPath.lineTo(ps[0], ps[1]); drawSth(); } } /** * 获取每个人脸的四点位置坐标 * * @param fre * @return */ private int[] getPositions(FaceBean.FacesEntity.Face_rectangleEntity fre) { int[] faces = new int[8]; faces[0] = fre.getLeft_top().getX(); faces[1] = fre.getLeft_top().getY(); faces[2] = fre.getRight_top().getX(); faces[3] = fre.getRight_top().getY(); faces[4] = fre.getRight_bottom().getX(); faces[5] = fre.getRight_bottom().getY(); faces[6] = fre.getLeft_bottom().getX(); faces[7] = fre.getLeft_bottom().getY(); for (int i = 0; i < faces.length; i++) { faces[i] *= 2; if (i % 2 == 0) { faces[i] = (640 * 2) - faces[i]; } } return faces; } private void drawSth() { try { mCanvas = mHolder.lockCanvas(); //拿到当前画布 然后锁定 mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR); mCanvas.drawPath(mPath, mPaint); } catch (Exception e) { e.printStackTrace(); } finally { if (mCanvas != null) { mHolder.unlockCanvasAndPost(mCanvas);//保证每次都将绘图的内容提交 } } }}
说明一下,多个SurfaceView叠加可能会遇到的问题, 请参考这篇博客。 mHolder = getHolder();//获取SurfaceHolder对象 //TODO:保证该SurfaceView在最上层,避免两个SurfaceView叠加,遮挡问题 mHolder.setFormat(PixelFormat.TRANSPARENT); setZOrderOnTop(true);
更多相关文章
- Android(安卓)ADB server didn't ACK 错误解决
- 【Android】TextView 显示超链接的几种方法
- Android(安卓)中部分文字高亮显示方法
- Android面试宝典(更新中)
- Android(安卓)WebView 详细介绍
- android之AsyncQueryHandler详解
- 在Android中afinal框架下实现sqlite数据库版本升级的办法
- Android中获取资源的id和url方法总结
- Android(安卓)build过程中already defined by packages/apps 的