自定义控件时经常用到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);

更多相关文章

  1. Android(安卓)ADB server didn't ACK 错误解决
  2. 【Android】TextView 显示超链接的几种方法
  3. Android(安卓)中部分文字高亮显示方法
  4. Android面试宝典(更新中)
  5. Android(安卓)WebView 详细介绍
  6. android之AsyncQueryHandler详解
  7. 在Android中afinal框架下实现sqlite数据库版本升级的办法
  8. Android中获取资源的id和url方法总结
  9. Android(安卓)build过程中already defined by packages/apps 的

随机推荐

  1. Android xutils 登录 注册
  2. cocos2dx编译HelloWorld
  3. Android(安卓)Studio使用说明
  4. android 画图程序
  5. Android 实现图片保存到本地并调用本地地
  6. Android 指定销毁一个Activity
  7. Android代码混淆
  8. android --相机使用详解概述
  9. android多dex打包问题
  10. Android简单实现加减乘除(两个EditText,两