前言

之前写过一个Android的画图类,自定义View实现的,其中的擦除效果很不自然,每次擦除都会将线条整条删除,而不是手指指到哪里就擦除哪里,很不自然。一直没有想明白如何做,直到看到了这篇文章:。 结合文章的方法和自己的理解进行了重写,完成了安卓的画图效果。

绘制顺序

如上图所示,首先是绘制的顺序:
原理很简单,首先我们将底层的Bitmap绘制出来,也就是绘制mCacheBitmap。
然后绘制列表中的路径,这是可以正常显示的路径,也就是绘制mPathList的内容。
最后设置了mErasePaint的Xfermode后进行下一步的绘制,我们通过如下设置mPorterDuffXfermode来设置DST_OUT的模式:

        mPorterDuffXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);        mErasePaint.setXfermode(mPorterDuffXfermode);

这也就是擦除的效果,可以参考前面贴出的博客,于是就绘制了mEraseList的内容。
更新:为了提高整体的速度,我们也可以使用clipRect方法。

    private void createBitmap() {        mBitmap = Bitmap.createBitmap(getMeasuredWidth(), getMeasuredHeight(), Bitmap.Config.ARGB_8888);        mCanvas = new Canvas(mBitmap);    }    public void onDraw(Canvas canvas) {        super.onDraw(canvas);        // 提高速度        canvas.clipRect(getPaddingLeft(), getPaddingTop(),                getRight(), getBottom());        if (mCacheBitmap != null)            mCanvas.drawBitmap(mCacheBitmap, 0, 0, null);        if (mPathList != null) {            for (int i = 0; i < mPathList.size(); i++) {                PathInfo pathInfo = mPathList.get(i);                mPaint.setStrokeWidth(pathInfo.width);                mPaint.setColor(pathInfo.color);                mCanvas.drawPath(pathInfo.path, mPaint);            }        }        mErasePaint.setXfermode(mPorterDuffXfermode);        mErasePaint.setStyle(Paint.Style.STROKE);        for (int i = 0; i < mEraseList.size(); i++) {            mErasePaint.setStrokeWidth(mEraseList.get(i).width);            mErasePaint.setColor(mEraseList.get(i).color);            mCanvas.drawPath(mEraseList.get(i).path, mErasePaint);        }        canvas.drawBitmap(mBitmap, 0, 0, null);    }

切换

当我们从绘制切换到擦除时,是不需要多余的操作的,因为我们的绘制过程是正常的绘制,直接绘制在画板上就可以了,而擦除则需要设置特殊的模式,两相结合也是没有问题的,因为我们的擦除是后绘制的。
而当从擦除切换到绘制时,就会有比较大的问题了,在切换时,我们首先要将目前的View的Bitmap导出,这样后面无论如何绘制都与前面的无关,不会有任何影响。
导出View的Bitmap:

    private void createViewBitmap() {        setDrawingCacheEnabled(true);        buildDrawingCache();        Bitmap bitmap = getDrawingCache();        if (bitmap != null)            mCacheBitmap = Bitmap.createBitmap(bitmap);        destroyDrawingCache();        setDrawingCacheEnabled(false);    }

然后要将绘制的路径列表和擦除列表都清空,去除前面的影响。然后再进行绘制。

路径判断

这里主要是讲讲如何进行Android的绘制,也就是触摸事件。首先我们是获得当前的点,并且要新建一个Path对象,这里我封装在PathInfo里了。:
手指按下事件:

    private void touch_down(float x, float y) {        mX = x;        mY = y;        Log.d("tag", x + " " + y);        mPathInfo = new PathInfo();        mPathInfo.path.moveTo(x, y);        mPathInfo.width = this.mWidth;        if (this.mMode == MODE_DRAW) {            mPathInfo.color = this.mColor;            mPathList.add(mPathInfo);        } else if (this.mMode == MODE_ERASE) {            mPathInfo.color = Color.WHITE;            mEraseList.add(mPathInfo);        }    }

手指移动事件:
每次调用lineTo方法就能绘制从起点到当前点的路径了。
注意要设置画笔的模式是STROKE。参考:

    private void touch_move(float x, float y) {        float dx = Math.abs(x - mX);        float dy = Math.abs(y - mY);        if (dx >= MAX_TOUCH || dy >= MAX_TOUCH) {            mPathInfo.path.lineTo(x, y);        }    }

onTouchEvent:

    public boolean onTouchEvent(MotionEvent event) {        float x = event.getX();        float y = event.getY();        switch (event.getAction()) {            case MotionEvent.ACTION_DOWN:                touch_down(x, y);                break;            case MotionEvent.ACTION_MOVE:                touch_move(x, y);                break;        }        invalidate();        return true;    }

效果图:

后记

本文简单的总结了一个小例子,放在github上,欢迎查看:https://github.com/zjtone/AndroidDrawing
更新:添加了修改宽度的功能。

更多相关文章

  1. android animation——view进入退出动画
  2. Android中nemu菜单的字体太小?如何设置actionbar中menu的text的s
  3. Android硬件加速绘制模型介绍
  4. Android(安卓)RecyclerView和ListView多布局实现
  5. win10下使用Fiddler进行网络抓包
  6. android 属性系统,SystemProperties 的简介
  7. Android(安卓)自定义View 绘制正N边形
  8. Android(安卓)TextView字体样式设置
  9. android 下使用GPS 无法获取经纬度的解决方法

随机推荐

  1. 【Android】线程/进程绑定指定CPU核
  2. Layout布局之相对布局
  3. Android(安卓)SQLite数据库中的表详解
  4. Android(安卓)Studio导入OpenCV Android(
  5. Android的线程使用来更新UI------Thread
  6. Eclipse开发Android应用程序入门:重装上
  7. 如何制作表格(一)——TableLayout
  8. Android-Jni线程(三)— JNI全局回调java方
  9. 【android】ListView的item高度调整
  10. 如何将一个Activity设置成窗口的样式