看过很多开源代码效果,发现里面的代码很多地方都用到这函数,于是想花些时间研究下这个,我现在写博客一般不可能一下子就写完,因为我也要查资料,写代码去验证其效果,而且还要找下好的效果,看能不能用这篇博客知识能实现出来的,整理出来,切入正题!
paint的setXfermode()是图形混合模式,多叫混合模式了,肯定是二张以上的图形才可以,看下Paint类中定义这个方法:
public Xfermode setXfermode(Xfermode xfermode) { long xfermodeNative = 0; if (xfermode != null) xfermodeNative = xfermode.native_instance; native_setXfermode(mNativePaint, xfermodeNative); mXfermode = xfermode; return xfermode; }发现函数中接受Xfermode形参,点击Xfermode类看看啥东西,
public class Xfermode { protected void finalize() throws Throwable { try { finalizer(native_instance); } finally { super.finalize(); } } private static native void finalizer(long native_instance); long native_instance; }什么玩意,就这几行代码,而且还有一个被native修饰的方法,这就超越了上层的知识结构,表示不懂,所以不看了,ctrl+T,发现有三个子类,
现在就分别讲一下这三个类怎么使用,以及其能实现什么效果
AvoidXfermode
这是一个关于颜色模式的类,这是我自己取得,网上很多叫--指定了一个颜色和容差,强制Paint避免在它上面绘图(或者只在它上面绘图),不管它叫什么,
看下AvoidXfermode的类
@Deprecated public class AvoidXfermode extends Xfermode { // these need to match the enum in AvoidXfermode.h on the native side public enum Mode { AVOID (0), //!< draw everywhere except on the opColor TARGET (1); //!< draw only on top of the opColor Mode(int nativeInt) { this.nativeInt = nativeInt; } final int nativeInt; } /** This xfermode draws, or doesn't draw, based on the destination's * distance from an op-color. * * There are two modes, and each mode interprets a tolerance value. * * Avoid: In this mode, drawing is allowed only on destination pixels that * are different from the op-color. * Tolerance near 0: avoid any colors even remotely similar to the op-color * Tolerance near 255: avoid only colors nearly identical to the op-color * Target: In this mode, drawing only occurs on destination pixels that * are similar to the op-color * Tolerance near 0: draw only on colors that are nearly identical to the op-color * Tolerance near 255: draw on any colors even remotely similar to the op-color */ public AvoidXfermode(int opColor, int tolerance, Mode mode) { if (tolerance < 0 || tolerance > 255) { throw new IllegalArgumentException("tolerance must be 0..255"); } native_instance = nativeCreate(opColor, tolerance, mode.nativeInt); } private static native long nativeCreate(int opColor, int tolerance, int nativeMode); }发现它都没有自己的方法,就是一个构造函数,
public AvoidXfermode(int opColor, int tolerance, Mode mode) { if (tolerance < 0 || tolerance > 255) { throw new IllegalArgumentException("tolerance must be 0..255"); } native_instance = nativeCreate(opColor, tolerance, mode.nativeInt); }参数说明:
int opColor:是一个16进制的颜色值
int tolerance:看的出来这个取值范围为[0,255]
Mode mode值在这个类下面定义了一个枚举就二种值一个是AVOID,一种是TARGET,
现在写一个例子更好里面上面三个参数,
package com.example.myapplication; import android.content.Context; import android.graphics.AvoidXfermode; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Paint; import android.util.AttributeSet; import android.view.View; /** * Created by admin on 2016/7/2. */ public class MyView extends View { private Paint mPaint; private Bitmap mBitmap; public MyView(Context context) { this(context,null); } public MyView(Context context, AttributeSet attrs) { this(context, attrs,0); } public MyView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(); } private void init() { mPaint = new Paint(); mBitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.bb); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setColor(Color.RED); canvas.drawBitmap(mBitmap,new Matrix(),mPaint); mPaint.setXfermode(new AvoidXfermode(Color.WHITE,100, AvoidXfermode.Mode.TARGET)); canvas.drawRect(0,0,mBitmap.getWidth(),mBitmap.getHeight(),mPaint); } }效果图:
尼玛发现这不是下面一个画布把上一个画布挡住了么,还什么混合模式,这个跟硬件加速有关,大家手机中设置界面有关一个叫GPU的东西吧,是不是和CPU很像啊,GPU的出现就是为了绘制图形图像的,在view中禁止GPU硬件加速的方法是:
setLayerType(View.LAYER_TYPE_SOFTWARE, null);这个在构造函数中设置就行现在再看下效果:
把硬件加速禁止了效果就出来了,看下onDraw()中的代码,canvas是2个画布,
现在我把AvoidXfermode构造函数中的第二个参数变一下,看下其效果,之前传的是100,现在传200,效果:
之前说了这个值最大是255,现在就把它设置为255
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setColor(Color.RED); canvas.drawBitmap(mBitmap,new Matrix(),mPaint); mPaint.setXfermode(new AvoidXfermode(Color.WHITE,255, AvoidXfermode.Mode.TARGET)); canvas.drawRect(0,0,mBitmap.getWidth(),mBitmap.getHeight(),mPaint); }效果:
现在传0试试:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setColor(Color.RED); canvas.drawBitmap(mBitmap,new Matrix(),mPaint); mPaint.setXfermode(new AvoidXfermode(Color.WHITE,0, AvoidXfermode.Mode.TARGET)); canvas.drawRect(0,0,mBitmap.getWidth(),mBitmap.getHeight(),mPaint); }效果:
发现0是透明的效果,现在看第三个形参Mode,这个是传递AvoidXfermode.Mode.TARGET
AvoidXfermode.Mode.TARGET:会判断画布(也就是canvas,而canvas颜色是通过Paint设置的)上的颜色是否会有跟opColor(AvoidXfermode构造函数第一个形参)有一样的颜色,比如我opColor是白色,那么在TARGET模式下就会去判断我们的画布上是否有存在白色的地方,如果有,则把该区域“染”上一层我们画笔定义的颜色,否则不“染”色
AvoidXfermode.Mode.AVOID:跟上面刚好相反,
PorterDuffXfermode
构造函数:
public PorterDuffXfermode(PorterDuff.Mode mode) { this.mode = mode; native_instance = nativeCreateXfermode(mode.nativeInt); }
发现构造函数就一个值,这些值是定义在PorterDuff类中
public enum Mode { /** [0, 0] */ CLEAR (0), /** [Sa, Sc] */ SRC (1), /** [Da, Dc] */ DST (2), /** [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] */ SRC_OVER (3), /** [Sa + (1 - Sa)*Da, Rc = Dc + (1 - Da)*Sc] */ DST_OVER (4), /** [Sa * Da, Sc * Da] */ SRC_IN (5), /** [Sa * Da, Sa * Dc] */ DST_IN (6), /** [Sa * (1 - Da), Sc * (1 - Da)] */ SRC_OUT (7), /** [Da * (1 - Sa), Dc * (1 - Sa)] */ DST_OUT (8), /** [Da, Sc * Da + (1 - Sa) * Dc] */ SRC_ATOP (9), /** [Sa, Sa * Dc + Sc * (1 - Da)] */ DST_ATOP (10), /** [Sa + Da - 2 * Sa * Da, Sc * (1 - Da) + (1 - Sa) * Dc] */ XOR (11), /** [Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + min(Sc, Dc)] */ DARKEN (16), /** [Sa + Da - Sa*Da, Sc*(1 - Da) + Dc*(1 - Sa) + max(Sc, Dc)] */ LIGHTEN (17), /** [Sa * Da, Sc * Dc] */ MULTIPLY (13), /** [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] */ SCREEN (14), /** Saturate(S + D) */ ADD (12), OVERLAY (15);发现一共有18个值,关于这里的算法我是不懂,但是我可以每个值我写个例子出来,看看效果,知道了什么意思,就可以写出来不一样的效果了就行
先看google文档给我们的一张图:
相信这张图大家在网上很容易看到,
这里有个概念就是DST和SRC,DST是指目标图形,SCR是指源图形,现在写个例子说明下:
package com.example.xfermode; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.RectF; import android.util.AttributeSet; import android.view.View; /** * Created by admin on 2016/7/4. */ public class MyView extends View { private int width = 200; private int height = 200; private Bitmap dstBmp; private Bitmap srcBmp; private Paint mPaint; public MyView(Context context, AttributeSet attrs) { super(context, attrs); dstBmp = getDSTBitmap(width,height); srcBmp = getSRCBitmap(width,height); mPaint = new Paint(); setLayerType(View.LAYER_TYPE_SOFTWARE, null);//禁止硬件加速 } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawBitmap(dstBmp, 0, 0, mPaint);//绘制目标图形,目标图形是一个圆 mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); canvas.drawBitmap(srcBmp, width/2, height/2, mPaint);//绘制源目标 mPaint.setXfermode(null);//将画笔去除Xfermode } public Bitmap getDSTBitmap(int w, int h) { Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm);//创建一个新的画布,以后在画布上绘制的图形都是绘制在bm上 Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); p.setColor(0xFFFFCC44); c.drawOval(new RectF(0, 0, w, h), p); return bm; } public Bitmap getSRCBitmap(int w, int h) { Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm); Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); p.setColor(0xFF66AAFF); c.drawRect(0, 0,w,h, p); return bm; } }效果:
如果不设置mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));这行代码看下效果是怎么样的,
通过上下二张图就看出来了paint设置xfermode()的效果来了,太强大了,
PorterDuffXfermode这个类中的Porter和Duff是两个人名,这两个人在1984年一起写了一篇名为《Compositing Digital Images》的论文,我们知道,一个像素是由RGBA四个分量组成的,该论文就论述了如何实现不同数字图像的像素之间是如何进行混合的,该论文提出了多种像素混合的模式
现在对什么是源图形和目标图形做个简单的说明:
说明一点,源图形可以是多个,比如下面:
package com.example.xfermode; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.RectF; import android.util.AttributeSet; import android.view.View; /** * Created by admin on 2016/7/4. */ public class MyView extends View { private int width = 200; private int height = 200; private Bitmap dstBmp; private Bitmap srcBmp; private Paint mPaint; public MyView(Context context, AttributeSet attrs) { super(context, attrs); dstBmp = getDSTBitmap(width,height); srcBmp = getSRCBitmap(width,height); mPaint = new Paint(); setLayerType(View.LAYER_TYPE_SOFTWARE, null);//禁止硬件加速 } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawBitmap(dstBmp, 0, 0, mPaint);//绘制目标图形,目标图形是一个圆 mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); canvas.drawBitmap(srcBmp, width/2, height/2, mPaint);//绘制源目标 mPaint.setColor(Color.RED); canvas.drawRect(0,0,100,100,mPaint); mPaint.setColor(Color.GREEN); canvas.drawRect(100,0,200,100,mPaint); mPaint.setXfermode(null);//将画笔去除Xfermode } public Bitmap getDSTBitmap(int w, int h) { Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm);//创建一个新的画布,以后在画布上绘制的图形都是绘制在bm上 Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); p.setColor(0xFFFFCC44); c.drawOval(new RectF(0, 0, w, h), p); return bm; } public Bitmap getSRCBitmap(int w, int h) { Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm); Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); p.setColor(0xFF66AAFF); c.drawRect(0, 0,w,h, p); return bm; } }效果图:
这个是不是有点像分布图,
一般我们在调用canvas.drawXXX()方法时都会传入一个画笔Paint对象,Android在绘图时会先检查该画笔Paint对象有没有设置Xfermode,如果没有设置Xfermode,那么直接将绘制的图形覆盖Canvas对应位置原有的像素;如果设置了Xfermode,那么会按照Xfermode具体的规则来更新Canvas中对应位置的像素颜色,关于具体的算法不懂,
发现我xfermode设置的是src_in模式和Google给的不一样,是不是Google错了,
上面讲了一个SRC_IN模式,现在把其他模式也讲下,
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawBitmap(dstBmp, 0, 0, mPaint);//绘制目标图形,目标图形是一个圆 mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD)); canvas.drawBitmap(srcBmp, width/2, height/2, mPaint);//绘制源目标 mPaint.setXfermode(null);//将画笔去除Xfermode }效果:
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawBitmap(dstBmp, 0, 0, mPaint);//绘制目标图形,目标图形是一个圆 mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN)); canvas.drawBitmap(srcBmp, width/2, height/2, mPaint);//绘制源目标 mPaint.setXfermode(null);//将画笔去除Xfermode }效果:
public class MyView3 extends View { private Paint mPaint; private Bitmap bitmap = null; public MyView3(Context context) { super(context); } public MyView3(Context context, AttributeSet attrs) { super(context, attrs); bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.aa); mPaint = new Paint(); } public MyView3(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawBitmap(bitmap, 0, 0, mPaint); mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.LIGHTEN)); mPaint.setColor(0x70ffffff); canvas.drawRect(0,0,bitmap.getWidth(),bitmap.getHeight(),mPaint); } }效果:
public class MyView3 extends View { private Paint mPaint; private Bitmap bitmap = null; public MyView3(Context context) { super(context); } public MyView3(Context context, AttributeSet attrs) { super(context, attrs); bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.aa); mPaint = new Paint(); } public MyView3(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawBitmap(bitmap, 0, 0, mPaint); mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DARKEN)); mPaint.setColor(0x70ffffff); canvas.drawRect(0,0,bitmap.getWidth(),bitmap.getHeight(),mPaint); } }效果:
public class MyView extends View { private int width = 200; private int height = 200; private Bitmap dstBmp; private Bitmap srcBmp; private Paint mPaint; public MyView(Context context, AttributeSet attrs) { super(context, attrs); dstBmp = getDSTBitmap(width,height); srcBmp = getSRCBitmap(width,height); mPaint = new Paint(); setLayerType(View.LAYER_TYPE_SOFTWARE, null);//禁止硬件加速 } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawBitmap(dstBmp, 0, 0, mPaint);//绘制目标图形,目标图形是一个圆 mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY)); canvas.drawBitmap(srcBmp, width/2, height/2, mPaint);//绘制源目标 mPaint.setXfermode(null);//将画笔去除Xfermode } public Bitmap getDSTBitmap(int w, int h) { Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm);//创建一个新的画布,以后在画布上绘制的图形都是绘制在bm上 Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); p.setColor(0xFFFFCC44); c.drawOval(new RectF(0, 0, w, h), p); return bm; } public Bitmap getSRCBitmap(int w, int h) { Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm); Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); p.setColor(0xFF66AAFF); c.drawRect(0, 0,w,h, p); return bm; } }效果:
public class MyView extends View { private int width = 200; private int height = 200; private Bitmap dstBmp; private Bitmap srcBmp; private Paint mPaint; public MyView(Context context, AttributeSet attrs) { super(context, attrs); dstBmp = getDSTBitmap(width,height); srcBmp = getSRCBitmap(width,height); mPaint = new Paint(); setLayerType(View.LAYER_TYPE_SOFTWARE, null);//禁止硬件加速 } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawBitmap(dstBmp, 0, 0, mPaint);//绘制目标图形,目标图形是一个圆 mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.OVERLAY)); canvas.drawBitmap(srcBmp, width/2, height/2, mPaint);//绘制源目标 mPaint.setXfermode(null);//将画笔去除Xfermode } public Bitmap getDSTBitmap(int w, int h) { Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm);//创建一个新的画布,以后在画布上绘制的图形都是绘制在bm上 Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); p.setColor(0xFFFFCC44); c.drawOval(new RectF(0, 0, w, h), p); return bm; } public Bitmap getSRCBitmap(int w, int h) { Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm); Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); p.setColor(0xFF66AAFF); c.drawRect(0, 0,w,h, p); return bm; } }效果:
public Bitmap getSRCBitmap(int w, int h) { Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm); Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); p.setColor(0x00ffffff); c.drawRect(0, 0,w,h, p); return bm; }效果:
public static Bitmap compoundBitmap(Context contxt, int resId){ Bitmap originalBitmap = BitmapFactory.decodeResource(contxt.getResources(),resId);//把资源图片变成一个Bitmap对象 //生成下面的一半图片 Matrix matrix = new Matrix(); matrix.setScale(1,-1); Bitmap invertBitmap = Bitmap.createBitmap(originalBitmap,0,originalBitmap.getHeight()/2,originalBitmap.getWidth(),originalBitmap.getHeight()/2,matrix,false); //创建一个空的位图 Bitmap compoundBitmap = Bitmap.createBitmap(originalBitmap.getWidth(),originalBitmap.getHeight()+invertBitmap.getHeight()+10, Bitmap.Config.ARGB_8888);//+10是为了2张图片之间有空隙 Canvas canvas = new Canvas(compoundBitmap); canvas.drawBitmap(originalBitmap,0,0,null); canvas.drawBitmap(invertBitmap,0,originalBitmap.getHeight()+10,null); Paint paint = new Paint(); // 设置渐变颜色 LinearGradient shader = new LinearGradient(0, originalBitmap.getHeight() + 5, 0, compoundBitmap.getHeight(), 0x70ffffff, 0x00ffffff, Shader.TileMode.CLAMP); paint.setShader(shader); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); canvas.drawRect(0, originalBitmap.getHeight() + 5, originalBitmap.getWidth(), compoundBitmap.getHeight(), paint); return compoundBitmap; }效果:
public class MyView3 extends View { private Paint mPaint; private Bitmap bitmap = null; private Bitmap srcBitmap = null; public MyView3(Context context) { super(context); } public MyView3(Context context, AttributeSet attrs) { super(context, attrs); srcBitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.dog_shade); mPaint = new Paint(); setLayerType(View.LAYER_TYPE_SOFTWARE, null);//禁止硬件加速 } public MyView3(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint.setColor(Color.GREEN); canvas.drawRect(10,10,100,100,mPaint); mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); mPaint.setColor(Color.RED); canvas.drawRect(10,10,100,100,mPaint); } }效果:
package com.example.xfermode; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.LinearGradient; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; /** * Created by admin on 2016/7/4. */ public class MyView3 extends View { private Paint mPaint; private Bitmap bitmap = null; private Bitmap srcBitmap = null; private Path mPath; private float firstDownX; private float firstDownY; public MyView3(Context context) { super(context); } public MyView3(Context context, AttributeSet attrs) { super(context, attrs); srcBitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.aa);//目标图片 //创建一个空位图 宽和高和源图片一样 bitmap = Bitmap.createBitmap(srcBitmap.getWidth(),srcBitmap.getHeight(), Bitmap.Config.ARGB_8888); mPaint = new Paint(); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(30); mPath = new Path(); setLayerType(View.LAYER_TYPE_SOFTWARE, null);//禁止硬件加速 } public MyView3(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); Canvas newCanvas = new Canvas();//创建一个画布 newCanvas.setBitmap(bitmap);//把一个空位图作用于画布上,以后在这个画布上绘制的图形都在这个位图上显示 newCanvas.drawPath(mPath,mPaint);//绘制路径 canvas.drawBitmap(bitmap,0,0,mPaint);//绘制目标图形 mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT)); canvas.drawBitmap(srcBitmap,0,0,mPaint);//绘制源图 } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: mPath.moveTo(event.getX(),event.getY()); firstDownX = event.getX(); firstDownY = event.getY(); break; case MotionEvent.ACTION_MOVE: float moveX = event.getX(); float moveY = event.getY(); float endX = (firstDownX+moveX)/2; float endY = (firstDownY+moveY)/2; mPath.quadTo(firstDownX,firstDownY,endX,endY); firstDownX = moveX; firstDownY =moveY; postInvalidate(); break; case MotionEvent.ACTION_UP: break; } return true; } }效果: