自定义控件---图层,画布和canvas
2017-11-09 14:34
381 查看
一: 概念
图层(Layer):
每一次调用canvas.drawXXX系列函数时,都会生成一个新的透明图层来专门来画这个图形,然后按照绘制的顺序覆盖到画布上。调用完方法就覆盖到画布上了。如果我们连续调用五个draw函数,那么就会生成五个透明图层,画完之后依次盖在画布上显示。
画布(bitmap):
每一个画布都是一个bitmap,所有的图像都是画在bitmap上的!
画布有两种,第一种是view的原始画布,是通过onDraw(Canvas canvas)函数传进来的,其中参数中的canvas就对应的是view的原始画布。 默认只有一个画布。
另一种是人造画布,通过saveLayer()、new Canvas(bitmap)这些方法来人为新建一个画布。
一旦调用saveLayer()新建一个画布以后,以后的所有draw函数所画的图像都是画在这个画布上的,只有当调用restore()、resoreToCount()函数以后,才会返回到原始画布上绘制。
双缓冲就是创建了新的画布。
Canvas:
我们可以把Canvas理解成画板,Bitmap理解成透明画纸,而Layer则理解成图层
每一个draw函数都对应一个图层,在一个图形画完以后,就放在画纸上显示。而一张张透明的画纸则一层层地叠加在画板上显示出来。我们知道画板和画纸都是用夹子夹在一起的,所以当我们旋转画板时,所有画纸都会跟着旋转!当我们把整个画板裁小时,所以的画纸也都会变小了! 这一点非常重要,当我们利用saveLayer来生成多个画纸时,然后最上层的画纸调用canvas.rotate(30)是把画板给旋转了,所有的画纸也都被旋转30度!这一点非常注意 另外,如果最上层的画纸调用canvas.clipRect()将画板裁剪了,那么所有的画纸也都会被裁剪。唯一能够恢复的操作是调用canvas.revert()把上一次的动作给取消掉! 但在利用canvas绘图与画板不一样的是,画布的影响只体现在以后的操作上,以前画上去的图像已经显示在屏幕上是不会受到影响的。
关系:
一个canvas可以创建多个画布。一个画布又对应多个图层。图层的内容都是绘制到画布上的。
二:saveLayer()
saveLayer()有两个函数:
[java] view
plain copy
/**
* 保存指定矩形区域的canvas内容
*/
public int saveLayer(RectF bounds, Paint paint, int saveFlags)
public int saveLayer(float left, float top, float right, float bottom,Paint paint, int saveFlags)
RectF bounds:要保存的区域的矩形。
int saveFlags:取值有:ALL_SAVE_FLAG、MATRIX_SAVE_FLAG、CLIP_SAVE_FLAG、HAS_ALPHA_LAYER_SAVE_FLAG、FULL_COLOR_LAYER_SAVE_FLAG、CLIP_TO_LAYER_SAVE_FLAG总共有这六个,其中ALL_SAVE_FLAG表示保存全部内容,这些标识的具体意义在其他章节介绍;
第二个构造函数实际与第一个是一样的,只不过是根据四个点来构造一个矩形。
下面我们来看一下例子,拿xfermode来做下试验,来看看saveLayer都干了什么:
[java] view
plain copy
public class XfermodeView extends View {
private int width = 400;
private int height = 400;
private Bitmap dstBmp;
private Bitmap srcBmp;
private Paint mPaint;
public XfermodeView(Context context, AttributeSet attrs) {
super(context, attrs);
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
srcBmp = makeSrc(width, height);
dstBmp = makeDst(width, height);
mPaint = new Paint();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.GREEN);
//创建了一个新的画布,大小就是矩形大小
int layerID = canvas.saveLayer(0, 0, width * 2, height * 2, mPaint, Canvas.ALL_SAVE_FLAG);
//创建新的图层
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);
//这之前的绘制都是画在新画布上的
canvas.restoreToCount(layerID);
//恢复到原始画布上绘制
}
// create a bitmap with a circle, used for the "dst" image
static Bitmap makeDst(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(0xFFFFCC44);
c.drawOval(new RectF(0, 0, w, h), p);
return bm;
}
// create a bitmap with a rect, used for the "src" image
static Bitmap makeSrc(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;
}
}
这段代码大家应该很熟悉,这是在讲解setXfermode()时的示例代码,但在saveLayer前把整个屏幕画成了绿色,效果图如下:
那么问题来了,如果我们把saveLayer给去掉,看看会怎样:
[java] view
plain copy
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.GREEN);
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);
}
效果图就变这样了:
先回顾下Mode.SRC_IN的效果:
在处理源图像时,以显示源图像为主,在相交时利用目标图像的透明度来改变源图像的透明度和饱和度。
当目标图像透明度为0时,源图像就完全不显示。
再回过来看结果,第一个结果是对的,因为不与圆相交以外的区域透明度都是0,而第二个图像怎么就变成了这屌样,源图像全部都显示出来了。
这是因为在调用saveLayer时,会生成了一个全新的透明的bitmap,这个bitmap的大小就是我们指定的保存区域的大小
在调用saveLayer后所有的draw操作都是在这个bitmap上进行的。
所以:
[java] view
plain copy
int layerID = canvas.saveLayer(0, 0, width * 2, height * 2, mPaint, Canvas.ALL_SAVE_FLAG);
canvas.drawBitmap(dstBmp, 0, 0, mPaint);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(srcBmp, width / 2, height / 2, mPaint);
saveLayer()有两个函数:
[java] view
plain copy
/**
* 保存指定矩形区域的canvas内容
*/
public int saveLayer(RectF bounds, Paint paint, int saveFlags)
public int saveLayer(float left, float top, float right, float bottom,Paint paint, int saveFlags)
RectF bounds:要保存的区域的矩形。
int saveFlags:取值有:ALL_SAVE_FLAG、MATRIX_SAVE_FLAG、CLIP_SAVE_FLAG、HAS_ALPHA_LAYER_SAVE_FLAG、FULL_COLOR_LAYER_SAVE_FLAG、CLIP_TO_LAYER_SAVE_FLAG总共有这六个,其中ALL_SAVE_FLAG表示保存全部内容,这些标识的具体意义我们后面会具体讲;
第二个构造函数实际与第一个是一样的,只不过是根据四个点来构造一个矩形。
下面我们来看一下例子,拿xfermode来做下试验,来看看saveLayer都干了什么:
[java] view
plain copy
public class XfermodeView extends View {
private int width = 400;
private int height = 400;
private Bitmap dstBmp;
private Bitmap srcBmp;
private Paint mPaint;
public XfermodeView(Context context, AttributeSet attrs) {
super(context, attrs);
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
srcBmp = makeSrc(width, height);
dstBmp = makeDst(width, height);
mPaint = new Paint();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.GREEN);
int layerID = canvas.saveLayer(0, 0, width * 2, height * 2, mPaint, Canvas.ALL_SAVE_FLAG);
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);
canvas.restoreToCount(layerID);
}
// create a bitmap with a circle, used for the "dst" image
static Bitmap makeDst(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(0xFFFFCC44);
c.drawOval(new RectF(0, 0, w, h), p);
return bm;
}
// create a bitmap with a rect, used for the "src" image
static Bitmap makeSrc(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;
}
}
这段代码大家应该很熟悉,这是我们在讲解setXfermode()时的示例代码,但在saveLayer前把整个屏幕画成了绿色,效果图如下:
那么问题来了,如果我们把saveLayer给去掉,看看会怎样:
[java] view
plain copy
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.GREEN);
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);
}
效果图就变这样了:
先回顾下Mode.SRC_IN的效果:在处理源图像时,以显示源图像为主,在相交时利用目标图像的透明度来改变源图像的透明度和饱和度。当目标图像透明度为0时,源图像就完全不显示。
再回过来看结果,第一个结果是对的,因为不与圆相交以外的区域透明度都是0,而第二个图像怎么就变成了这屌样,源图像全部都显示出来了。
这是因为在调用saveLayer时,会生成了一个全新的bitmap,这个bitmap的大小就是我们指定的保存区域的大小,新生成的bitmap是全透明的,在调用saveLayer后所有的绘图操作都是在这个bitmap上进行的。
所以:
[java] view
plain copy
//生成新的画布
int layerID = canvas.saveLayer(0, 0, width * 2, height * 2, mPaint, Canvas.ALL_SAVE_FLAG);
//新的图层绘制目的图像,然后覆盖到新的画布上
canvas.drawBitmap(dstBmp, 0, 0, mPaint);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
//新的图层绘制原图像,然后覆盖到新的画布上
canvas.drawBitmap(srcBmp, width / 2, height / 2, mPaint);
在画源图像时,会把之前画布上所有的内容都做为目标图像,而在saveLayer新生成的bitmap上,只有dstBmp对应的圆形,所以除了与圆形相交之外的位置都是空像素。
这2个绘制都是在新的画布上。然后调用restoreToCount的时候
会把saveLayer所生成的bitmap盖在原来的canvas上面。
所以此时的xfermode的合成过程如下图所示:
然后我们再来看第二个示例,在第二个示例中,唯一的不同就是把saveLayer去掉了;
在saveLayer去掉后,所有的绘图操作都放在了原始View的Canvas所对应的Bitmap上了
只有一个画布
[java] view
plain copy
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.GREEN);
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来画源图像的时候,目标图像当前Bitmap上的所有图像,也就是整个绿色的屏幕和一个圆形了。
所以这时候源图像的相交区域是没有透明像素的,透明度全是100%,这也就不难解释结果是这样的原因了。
此时的xfermode合成过程如下:
由于没有调用saveLayer,所以圆形是直接画在原始画布上的,而当矩形与其相交时,就是直接与原始画布上的所有图像做计算的。 只有一个画布,则每draw一个图像就直接覆盖到的当前画布上了。
所以有关saveLayer的结论来了:
saveLayer会创建一个全新透明的bitmap,大小与指定保存的区域一致,其后的绘图操作都放在这个bitmap上进行。
在绘制结束后,会直接盖在上一层的Bitmap上显示。
画布有多大就只能绘制多大的内容,超出画布的内容绘制不生效
创建新画布的时候,一定要选择适当的大小,屏幕大小的画布很浪费内存。很可能OOM。
图层(Layer):
每一次调用canvas.drawXXX系列函数时,都会生成一个新的透明图层来专门来画这个图形,然后按照绘制的顺序覆盖到画布上。调用完方法就覆盖到画布上了。如果我们连续调用五个draw函数,那么就会生成五个透明图层,画完之后依次盖在画布上显示。
画布(bitmap):
每一个画布都是一个bitmap,所有的图像都是画在bitmap上的!
画布有两种,第一种是view的原始画布,是通过onDraw(Canvas canvas)函数传进来的,其中参数中的canvas就对应的是view的原始画布。 默认只有一个画布。
另一种是人造画布,通过saveLayer()、new Canvas(bitmap)这些方法来人为新建一个画布。
一旦调用saveLayer()新建一个画布以后,以后的所有draw函数所画的图像都是画在这个画布上的,只有当调用restore()、resoreToCount()函数以后,才会返回到原始画布上绘制。
双缓冲就是创建了新的画布。
Canvas:
我们可以把Canvas理解成画板,Bitmap理解成透明画纸,而Layer则理解成图层
每一个draw函数都对应一个图层,在一个图形画完以后,就放在画纸上显示。而一张张透明的画纸则一层层地叠加在画板上显示出来。我们知道画板和画纸都是用夹子夹在一起的,所以当我们旋转画板时,所有画纸都会跟着旋转!当我们把整个画板裁小时,所以的画纸也都会变小了! 这一点非常重要,当我们利用saveLayer来生成多个画纸时,然后最上层的画纸调用canvas.rotate(30)是把画板给旋转了,所有的画纸也都被旋转30度!这一点非常注意 另外,如果最上层的画纸调用canvas.clipRect()将画板裁剪了,那么所有的画纸也都会被裁剪。唯一能够恢复的操作是调用canvas.revert()把上一次的动作给取消掉! 但在利用canvas绘图与画板不一样的是,画布的影响只体现在以后的操作上,以前画上去的图像已经显示在屏幕上是不会受到影响的。
关系:
一个canvas可以创建多个画布。一个画布又对应多个图层。图层的内容都是绘制到画布上的。
二:saveLayer()
saveLayer()有两个函数:
[java] view
plain copy
/**
* 保存指定矩形区域的canvas内容
*/
public int saveLayer(RectF bounds, Paint paint, int saveFlags)
public int saveLayer(float left, float top, float right, float bottom,Paint paint, int saveFlags)
RectF bounds:要保存的区域的矩形。
int saveFlags:取值有:ALL_SAVE_FLAG、MATRIX_SAVE_FLAG、CLIP_SAVE_FLAG、HAS_ALPHA_LAYER_SAVE_FLAG、FULL_COLOR_LAYER_SAVE_FLAG、CLIP_TO_LAYER_SAVE_FLAG总共有这六个,其中ALL_SAVE_FLAG表示保存全部内容,这些标识的具体意义在其他章节介绍;
第二个构造函数实际与第一个是一样的,只不过是根据四个点来构造一个矩形。
下面我们来看一下例子,拿xfermode来做下试验,来看看saveLayer都干了什么:
[java] view
plain copy
public class XfermodeView extends View {
private int width = 400;
private int height = 400;
private Bitmap dstBmp;
private Bitmap srcBmp;
private Paint mPaint;
public XfermodeView(Context context, AttributeSet attrs) {
super(context, attrs);
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
srcBmp = makeSrc(width, height);
dstBmp = makeDst(width, height);
mPaint = new Paint();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.GREEN);
//创建了一个新的画布,大小就是矩形大小
int layerID = canvas.saveLayer(0, 0, width * 2, height * 2, mPaint, Canvas.ALL_SAVE_FLAG);
//创建新的图层
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);
//这之前的绘制都是画在新画布上的
canvas.restoreToCount(layerID);
//恢复到原始画布上绘制
}
// create a bitmap with a circle, used for the "dst" image
static Bitmap makeDst(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(0xFFFFCC44);
c.drawOval(new RectF(0, 0, w, h), p);
return bm;
}
// create a bitmap with a rect, used for the "src" image
static Bitmap makeSrc(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;
}
}
这段代码大家应该很熟悉,这是在讲解setXfermode()时的示例代码,但在saveLayer前把整个屏幕画成了绿色,效果图如下:
那么问题来了,如果我们把saveLayer给去掉,看看会怎样:
[java] view
plain copy
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.GREEN);
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);
}
效果图就变这样了:
先回顾下Mode.SRC_IN的效果:
在处理源图像时,以显示源图像为主,在相交时利用目标图像的透明度来改变源图像的透明度和饱和度。
当目标图像透明度为0时,源图像就完全不显示。
再回过来看结果,第一个结果是对的,因为不与圆相交以外的区域透明度都是0,而第二个图像怎么就变成了这屌样,源图像全部都显示出来了。
(1)saveLayer的绘图流程
这是因为在调用saveLayer时,会生成了一个全新的透明的bitmap,这个bitmap的大小就是我们指定的保存区域的大小在调用saveLayer后所有的draw操作都是在这个bitmap上进行的。
所以:
[java] view
plain copy
int layerID = canvas.saveLayer(0, 0, width * 2, height * 2, mPaint, Canvas.ALL_SAVE_FLAG);
canvas.drawBitmap(dstBmp, 0, 0, mPaint);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
canvas.drawBitmap(srcBmp, width / 2, height / 2, mPaint);
saveLayer()
saveLayer()有两个函数:[java] view
plain copy
/**
* 保存指定矩形区域的canvas内容
*/
public int saveLayer(RectF bounds, Paint paint, int saveFlags)
public int saveLayer(float left, float top, float right, float bottom,Paint paint, int saveFlags)
RectF bounds:要保存的区域的矩形。
int saveFlags:取值有:ALL_SAVE_FLAG、MATRIX_SAVE_FLAG、CLIP_SAVE_FLAG、HAS_ALPHA_LAYER_SAVE_FLAG、FULL_COLOR_LAYER_SAVE_FLAG、CLIP_TO_LAYER_SAVE_FLAG总共有这六个,其中ALL_SAVE_FLAG表示保存全部内容,这些标识的具体意义我们后面会具体讲;
第二个构造函数实际与第一个是一样的,只不过是根据四个点来构造一个矩形。
下面我们来看一下例子,拿xfermode来做下试验,来看看saveLayer都干了什么:
[java] view
plain copy
public class XfermodeView extends View {
private int width = 400;
private int height = 400;
private Bitmap dstBmp;
private Bitmap srcBmp;
private Paint mPaint;
public XfermodeView(Context context, AttributeSet attrs) {
super(context, attrs);
setLayerType(View.LAYER_TYPE_SOFTWARE, null);
srcBmp = makeSrc(width, height);
dstBmp = makeDst(width, height);
mPaint = new Paint();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.GREEN);
int layerID = canvas.saveLayer(0, 0, width * 2, height * 2, mPaint, Canvas.ALL_SAVE_FLAG);
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);
canvas.restoreToCount(layerID);
}
// create a bitmap with a circle, used for the "dst" image
static Bitmap makeDst(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(0xFFFFCC44);
c.drawOval(new RectF(0, 0, w, h), p);
return bm;
}
// create a bitmap with a rect, used for the "src" image
static Bitmap makeSrc(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;
}
}
这段代码大家应该很熟悉,这是我们在讲解setXfermode()时的示例代码,但在saveLayer前把整个屏幕画成了绿色,效果图如下:
那么问题来了,如果我们把saveLayer给去掉,看看会怎样:
[java] view
plain copy
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.GREEN);
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);
}
效果图就变这样了:
先回顾下Mode.SRC_IN的效果:在处理源图像时,以显示源图像为主,在相交时利用目标图像的透明度来改变源图像的透明度和饱和度。当目标图像透明度为0时,源图像就完全不显示。
再回过来看结果,第一个结果是对的,因为不与圆相交以外的区域透明度都是0,而第二个图像怎么就变成了这屌样,源图像全部都显示出来了。
(1)、saveLayer的绘图流程
这是因为在调用saveLayer时,会生成了一个全新的bitmap,这个bitmap的大小就是我们指定的保存区域的大小,新生成的bitmap是全透明的,在调用saveLayer后所有的绘图操作都是在这个bitmap上进行的。 所以:
[java] view
plain copy
//生成新的画布
int layerID = canvas.saveLayer(0, 0, width * 2, height * 2, mPaint, Canvas.ALL_SAVE_FLAG);
//新的图层绘制目的图像,然后覆盖到新的画布上
canvas.drawBitmap(dstBmp, 0, 0, mPaint);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
//新的图层绘制原图像,然后覆盖到新的画布上
canvas.drawBitmap(srcBmp, width / 2, height / 2, mPaint);
在画源图像时,会把之前画布上所有的内容都做为目标图像,而在saveLayer新生成的bitmap上,只有dstBmp对应的圆形,所以除了与圆形相交之外的位置都是空像素。
这2个绘制都是在新的画布上。然后调用restoreToCount的时候
会把saveLayer所生成的bitmap盖在原来的canvas上面。
所以此时的xfermode的合成过程如下图所示:
(2)、没有saveLayer的绘图流程
然后我们再来看第二个示例,在第二个示例中,唯一的不同就是把saveLayer去掉了; 在saveLayer去掉后,所有的绘图操作都放在了原始View的Canvas所对应的Bitmap上了
只有一个画布
[java] view
plain copy
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.GREEN);
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来画源图像的时候,目标图像当前Bitmap上的所有图像,也就是整个绿色的屏幕和一个圆形了。
所以这时候源图像的相交区域是没有透明像素的,透明度全是100%,这也就不难解释结果是这样的原因了。
此时的xfermode合成过程如下:
由于没有调用saveLayer,所以圆形是直接画在原始画布上的,而当矩形与其相交时,就是直接与原始画布上的所有图像做计算的。 只有一个画布,则每draw一个图像就直接覆盖到的当前画布上了。
所以有关saveLayer的结论来了:
saveLayer会创建一个全新透明的bitmap,大小与指定保存的区域一致,其后的绘图操作都放在这个bitmap上进行。
在绘制结束后,会直接盖在上一层的Bitmap上显示。
画布有多大就只能绘制多大的内容,超出画布的内容绘制不生效
创建新画布的时候,一定要选择适当的大小,屏幕大小的画布很浪费内存。很可能OOM。
相关文章推荐
- 自定义控件之绘图篇:Canvas与图层(一)
- 自定义控件之绘图篇:Canvas与图层(二)
- android自定义控件画布canvas背景色失效变黑色
- 自定义控件设置canvas画布的大小
- 自定义控件三部曲之绘图篇(十三)——Canvas与图层(一)
- 自定义控件三部曲之绘图篇(十三)——Canvas与图层(一)
- 自定义控件三部曲之绘图篇(十四)——Canvas与图层(二)
- 自定义控件三部曲之绘图篇(十四)——Canvas与图层(二)
- Android 自定义控件canvas- Layer图层
- canvas绑定事件的时候 获得鼠标点击的地方在canvas画布内的坐标的方法
- canvas画布属性globalAlpha 和 createRadialGradient函数出现的设置问题
- 自定义控件详解(三):Canvas效果变换
- div标签、html/css基本样式、canvas画布
- 微信小程序开发之画布canvas 饼状图
- 【Android】自定义View、画布Canvas与画笔Paint
- 【一天一个canvas】Canvas画布调整之移动、缩放、旋转(九)
- 【Android】自定义View、画家(画布)Canvas与画笔Paint的应用——画图、涂鸦板app的实现
- 使用TiledLayer类及Canvas类实现游戏背景图层 推荐
- 关于4.6.x版本的UGUI的学习随笔之——Canvas(画布)
- 画布canvas,表单选项,随机矩形和圆,文字图像表示