概述:

很早之前就想研究一下Android中的涂鸦,其实也说不上是研究了,毕竟都是一些相对比较简单的知识点。下面就对基于画布(Canvas)和触摸事件(onTouchEvent)来实现涂鸦和刮刮乐。


参考:

http://blog.csdn.net/lmj623565791/article/details/40162163

此人的博客的确很好,想学习的同学也可以去参考一下这个大牛的其他博客。

http://blog.csdn.net/t12x3456/article/details/10432935


示例分析:

以下是两个简单的入门示例:涂鸦技术和刮刮乐的一些简单分析和效果展示。


1.涂鸦

思路分析及代码展示

学习过Canvas的同学应该都知道我们可以通过在一个View上覆盖一个canvas,并实现View的onTouchEvent方法就可以在Canvas上留下触摸屏幕时的轨迹,对于轨迹的记录还有一个类需要去了解——Path。关于Canvas更多的知识请点击这里查看。

Android在绘制界面的时候会获得布局中控件的大小、位置等参数之后再去绘制。而这里我们只是通过onMeasure和onDraw来绘制,没有用到onLayout是因为这里只有一个控件,没有太多动态布局需要处理。对于路径的记录则需要onTouchEvent实现。

测量大小:

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        int width = getMeasuredWidth();        int height = getMeasuredHeight();                // 初始化bitmap        mBitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);        mCanvas = new Canvas(mBitmap);    }

绘制:

protected void onDraw(Canvas canvas) {        drawPath();        canvas.drawBitmap(mBitmap, 0, 0, null);    }

路径绘制:

我们通过Path保存我们触摸的路径轨迹。如下:

private void drawPath() {        mFingerPaint.setStyle(Paint.Style.STROKE);        mCanvas.drawPath(mPath, mFingerPaint);    }

触摸事件:

对于触摸事件有一个非常重要而且不可忽视的类就是MotionEvent。它有以下三个常用的动作事件:

1.MotionEvent.ACTION_DOWN // 触摸按下时

2.MotionEvent.ACTION_MOVE // 触摸在移动过程中

3.MotionEvent.ACTION_UP // 触摸离开时


下面就看看onTouchEvent事件的实现过程:

public boolean onTouchEvent(MotionEvent event) {        int action = event.getAction();        int x = (int) event.getX();        int y = (int) event.getY();        switch (action) {        case MotionEvent.ACTION_DOWN:            actionMotionEventDown(x, y);            break;                    case MotionEvent.ACTION_MOVE:            actionMotionEventMove(x, y);            break;        }        invalidate();        return true;    }

上面的代码中,我们在按下的时候实现了按下的逻辑,在手指在屏幕上移动的时候实现了Move的逻辑。 还有别忘了invalidate()。invalidate()函数的主要作用是请求View树进行重绘,如果你不去调用它,结果就是什么事情都不会发生。


效果图



2.刮刮乐

思路分析及代码展示

分析:其实刮刮乐的实现思路跟涂鸦很像,都是在一块地方瞎画,并留下痕迹(说笑了,不过也不无道理。^_^)。不过有一点不同的就是我们在刮刮乐的绘制过程中画笔经过的地方,是变成了透明的了。这里你可能会说,那简单了,不就是要我去覆盖两层图片,在去绘制触摸路径,只是触摸路径的颜色是透明的。真的是这样的么?你可以试一试。当然,这样是行不通的,关于实践的最终效果大家可以自行尝试。这里的关键点在于我们要把上面的蒙层擦除且保留下面的底层。这里就用到了图形混合技术了。

图形混合技术一听名称是不是就是感觉很高深,不过的确是很牛的技术,不过Java已经给我们封装好了,我们只要知道怎么使用即可,而使用它则就不那么艰难了。

关于图形混合的详细描述,大家可以参考这里,我就不重复制造轮子了。不过我还是要简单介绍一下Xfermode三个子类下的一个:PorterDuffXfermode。这是一个非常强大的转换模式,使用它,可以使用图像合成的16条Porter-Duff规则的任意一条来控制Paint如何与已有的Canvas图像进行交互。


Porter-Duff规则如下:


PorterDuff.Mode为枚举类,一共有16个枚举值:
1.PorterDuff.Mode.CLEAR
所绘制不会提交到画布上。
2.PorterDuff.Mode.SRC
显示上层绘制图片
3.PorterDuff.Mode.DST
显示下层绘制图片
4.PorterDuff.Mode.SRC_OVER
正常绘制显示,上下层绘制叠盖。
5.PorterDuff.Mode.DST_OVER
上下层都显示。下层居上显示。
6.PorterDuff.Mode.SRC_IN
取两层绘制交集。显示上层。
7.PorterDuff.Mode.DST_IN
取两层绘制交集。显示下层。
8.PorterDuff.Mode.SRC_OUT
取上层绘制非交集部分。
9.PorterDuff.Mode.DST_OUT
取下层绘制非交集部分。
10.PorterDuff.Mode.SRC_ATOP
取下层非交集部分与上层交集部分
11.PorterDuff.Mode.DST_ATOP
取上层非交集部分与下层交集部分
12.PorterDuff.Mode.XOR
异或:去除两图层交集部分
13.PorterDuff.Mode.DARKEN
取两图层全部区域,交集部分颜色加深
14.PorterDuff.Mode.LIGHTEN
取两图层全部,点亮交集部分颜色
15.PorterDuff.Mode.MULTIPLY
取两图层交集部分叠加后颜色
16.PorterDuff.Mode.SCREEN
取两图层全部区域,交集部分变为透明色


我们需要的正是:DstOut这一条。代码中我们是这样实现的:

private void drawPath() {        mFingerPaint.setStyle(Paint.Style.STROKE);        // 设置两张图片相交时的模式(取下层绘制非交集部分)        mFingerPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));        mCanvas.drawPath(mPath, mFingerPaint);    }

测量和绘制过程如下:

@Override    protected void onDraw(Canvas canvas) {        canvas.drawText(mText, getWidth() / 2 - mTextBound.width() / 2, getHeight() / 2 + mTextBound.height() / 2, mBackPint);                if (!isComplete) {            drawPath();            canvas.drawBitmap(mBitmap, 0, 0, null);        }    }    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        int width = getMeasuredWidth();        int height = getMeasuredHeight();                // 初始化bitmap        mBitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);        mCanvas = new Canvas(mBitmap);        // 绘制遮盖层        mFingerPaint.setStyle(Paint.Style.FILL);        mCanvas.drawRoundRect(new RectF(0, 0, width, height), 30, 30, mFingerPaint);        mCanvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.mask), null, new RectF(0, 0, width, height), null);    }

此外还有一篇也是使用了此技术的博客,点击 这里进行查看。


效果图



源码下载:

http://download.csdn.net/detail/u013761665/8737527

更多相关文章

  1. android模拟器无法启动问题之中文路径
  2. android Thumbnail攻略
  3. 在eclipse中添加插件Green UML
  4. 如何解决:Android中 Error generating final archive: Debug Cert
  5. Gradle sync failed: Cause: error in opening zip file 几个可
  6. Android中sdk下载,虚拟机下载,Android环境配置
  7. Cordova+Vue整合到android studio上实现开发Android(安卓)APP
  8. 64位win7下Android(安卓)SDK Manager闪退的解决方法
  9. android初次学习(android studio安装及注意事项 1.5版本)

随机推荐

  1. android常用功能组件——setRequestedOri
  2. [置顶] Android系统安全之旅 第1章 编译A
  3. Android(安卓)BitmapFactory.Options 介
  4. android中showSoftInput不起作用
  5. Android群英传第五章笔记·Android(安卓)
  6. Android:捕捉触摸屏手势
  7. android 主要镜像(image)解析
  8. Android的第三个应用---短信发送器
  9. Android(安卓)的网络编程
  10. Android(安卓)截图实现