首页 > 其他分享 >Canvas与图层(二)画布与图层

Canvas与图层(二)画布与图层

时间:2023-01-06 10:34:57浏览次数:42  
标签:Canvas saveLayer canvas 画布 FLAG 图层 SAVE


图层(Layer):
  • 每次调用canvas.drawXXX系列函数,都会生成一个透明图层来绘制这个图形
画布(Bitmap):
  • 每块画布都是一个Bitmap,所有的图像都是画在这个Bitmap上的,画布有两种:
    * 一种是View的原始画布,通过onDraw(Canvas canvas)的方法传入的,canvas对应的就是原始的画布,控件的背景就是华仔这块 画布上的
    * 另一种是人造画布,通过saveLayer()、new Canvas(bitmap)等函数来人为的创建一块新的画布,调用saveLayer()函数以后所有的绘图都是在新创建出来的画布上进行的,只有在调用restore()、restoreToCount()之后才会返回原始的界面
Canvas:
  • Canvas是画布的表现形式,所绘制的所有东西都是通过Canvas实现的,可以将Canvas理解成绘图的工具,生成Canvas的方式只有一种new Canvas(Bitmap),即只能通过Bitmap生成,无论是原始画布还是人造画布,所有的画布最后都是通过Canvas画到画布上的。Canvas这个工具利用他封装的函数进行绘图操作,其实就是在对应的Bitmap上进行绘图操作,如果利用Canvas.clipXXX函数进行剪裁,就是剪裁对应的Bitmap,之后再利用Canvas的绘图区域就会变小。
总结:

Bitmap是画布 -->Canvas在Bitmap上绘图
Bitmap画布–>Layer产生图层–>Canvas绘图–>覆盖在画布上显示

saveLayer()和saveLayerAlpha()函数:

saveLayer()
//bounds:新建画布的尺寸
//paint:画笔实例
//saveFlags:新建画布的标识
public int saveLayer(RectF bounds, Paint paint, int saveFlags)
  • saveLayer()会新建一个新的画布,之后所有的绘图动作都会在新的画布上进行
注意:

(1) saveLayer()函数后的所有动作都只对新建画布有效

public class SaveLayerUseExample extends View {
private Paint paint;
private Bitmap bitmap;
public SaveLayerUseExample(Context context, AttributeSet attrs) {
super(context, attrs);
paint = new Paint();
paint.setColor(Color.RED);
bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.dog);


}


@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(bitmap, 0, 0, paint);
int layerId = canvas.saveLayer(0, 0, getWidth(), getHeight(), paint, Canvas.ALL_SAVE_FLAG);
//将新建的图层水平斜切45度,在进行绘画一个矩形,但是只是对新建的画布产生影响,并不会对原有的画布有影响
canvas.skew(1.732f, 0);
canvas.drawRect(0, 0, 150, 160, paint);
canvas.restoreToCount(layerId);


}
}

(2)通过Rect指定矩形大小就是新建的画布大小:

在saveLayer()函数的参数中,可以通过指定Rect对象或者指定4个点来指定一个矩形,这个矩形的大小就是新建的画布大小,而且在创建画布的时候一定要选择适当的大小,否则APP会发生OOM
setLayerAlpha()函数的使用:
//相比于saveLayer()函数,多了一个alpha的参数,用于指定新建画布的透明度,取值范围0~255,可以使用16进制的oxAA表示,取0时表示全透明
public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags)

public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha, int saveFlags)
  • saveLayerAlpha()会创建一个新的画布,以后的绘图就在这个新建的画布上完成,但是这块画布是有透明度的,通过alpha参数进行指定

eg:

@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(bitmap, 0, 0, paint);
int layerId = canvas.saveLayerAlpha(0, 0, 200, 200, 100, Canvas.ALL_SAVE_FLAG);
canvas.drawColor(Color.GRAY);
canvas.restoreToCount(layerId);
}
}
Flag的具体含义:
  • Canvas中有以下几个save系列函数:
public int save();
public int save(int saveFlags)
public int saveLayer(RectF bounds, Paint paint, int saveFlags)
public int saveLayer(float left, float top, float right , float bottom, Paint paint, int saveFlags)
public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags)
public int saveLayerAlpha(float left, float top. float right, float bottom, int alpha, int saveFalgs)
  • save()和saveLayer()区别:
save不会创建一个画布,saveLayer创建一个新的画布
  • save()和saveLayer()的flag的区别:

Flag

含义

适用范围

ALL_SAVE_FLAG

保存所有的标识

save()、saveLayer()

MATRIX_SAVE_FLAG

仅保存Canvas的matrix数组大小

save()、saveLayer()

CLIP_SAVE_FLAG

仅保存Canvas的当前大小

save(), saveLayer()

HAS_ALPHA_LAYER_SAVE_FLAG

标识新建的bmp具有透明度,在与上层画布结合的时候,透明位置显示上层图像,与FULL_COLOR_LAYER_SAVE_FLAG冲突,若同时指定,则以HAS_ALPHA_LAYER_SAVE_FLAG为主

saveLayer()

FULL_COLOR_LAYER_SAVE_FLAG

标识新建的bmp颜色完全独立,在与上层的画布结合的时候,先清空上层画布再覆盖上去

saveLayer()

CLIP_TO_LAYER_SAVE_FLAG

在保存图层前先把当前画布根据bounds剪裁,与CLIP_SAVE_FLAG冲突,若同时指定,则以CLIP_SAVE_FLAG为主

saveLayer()

注意:在保存一块画布的状态的时候,需要保存哪些内容
  • 位置信息:MATRIX_SAVE_FLAG
  • 大小信息:CLIP_SAVE_FLAG
Flag之MATRIX_SAVE_FLAG
  • 平移,旋转,缩放,扭曲都是利用位置矩阵Matrix实现的,而MATRIX_SAVE_FLAG标识仅保存这个位置矩阵,除此之外的任何内容都不会进行保存
public class MATRIX_SAVE_FLAG_View extends View {
private Paint paint;
public MATRIX_SAVE_FLAG_View(Context context, AttributeSet attrs) {
super(context, attrs);
setLayerType(LAYER_TYPE_SOFTWARE, null);
paint = new Paint();
}


@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);


//bao保存画布的位置信息
canvas.save();
//将画布旋转40度
canvas.rotate(40);
//画一个矩形
canvas.drawRect(100, 0, 200, 100, paint);
//恢复画布
canvas.restore();
paint.setColor(Color.BLACK);
canvas.drawRect(100, 0, 200, 100, paint);
}
}
  • 首先将画布的位置信息保存,然后绘制一个矩形,之后将画布恢复,在最后一个位置绘制 一个矩形,分析结果可以得知之前的保存操作是将画布的位置信息保存,但是如果使用MATRIX_SAVE_FLAG的flag进行保存,则不会保存画布的大小信息,也就是说裁剪之后的画布是不会被复原的
结论:
  • MATRIX_SAVE_FLAG标识只会保存位置矩阵,在恢复时也只会恢复画布的位置信息,除此之外的任何信息(比如画布的大小信息是不会被恢复的,save()和saveLayer()相同
  • saveLayer()函数在使用Canvas.MATRIX_SAVE_FLAG标识时,需要与Canvas.HAS_ALPHA_LAYER_SAVE_FLAG一起使用,否则新建画布所在区域原来的图像将被清空
Flag之CLIP_SAVE_FLAG
  • 这个标识是仅保存Canvas的裁剪信息,并不保存位置信息,只会恢复大小,并不会恢复旋转,位置信息
canvas.save(Canvas.CLIP_SAVE_FLAG);
canvas.drawColor(Color.BLUE);
canvas.clipRect(100, 0, 200, 100);
canvas.restore();
canvas.drawColor(Color.GRAY);
  • 首先将画布绘制蓝色并保存,再进行裁剪,裁剪后恢复,并画布绘制成灰色,最后发现全屏为灰色,则证明裁剪的画布被恢复。但是当你先绘制一个矩形,之后按照此flag保存画布,旋转40度后再恢复,再绘制一个矩形,会发现绘制的矩形旋转40度,所以证明这个flag只会对裁剪进行恢复,并不会对位置的信息进行恢复
结论:
  • CLIP_SAVE_FLAG:只会保存剪裁的信息,再恢复时也只会恢复画布的裁剪信息,除此之外的任何信息是不会被恢复的,save()和saveLayer()相同
  • saveLayer()函数在使用Canvas.CLIP_SAVE_FLAG标识时,需要与Canvas.HAS_ALPHA_LAYER_SAVE_FLAG标识一起使用,否则新建 画布所在区域的原来的图像将被清空
flag之FULL_COLOR_LAYER_FLAG和HAS_ALPHA_LAYER_SAVE_FLAG
  • HAS_ALPHA_LAYER_SAVE_FLAG:表示新建的画布在与上一层画布合成时,不会将上一层画布的内容清空,而是直接覆盖在上一层画布上的
  • FULL_COLOR_LAYER_FLAG:表示新建的画布在与上一层画布合成时,先将上一层画布的对应区域清空,再覆盖在上面
  1. 这两个标签都是saveLayer()专用,使用时要禁用硬件加速,在API26以及以后的版本中,该falg已经失效
  2. 两者是冲突的,使用时以HAS_ALPHA_LAYER_SAVE_FLAG为主
  3. 当既没有指定使用的是两者中的哪一个时,默认以FULL_COLOR_LAYER_SAVE_FLAG标识
flag之CLIP_TO_LAYER_SAVE_FLAG:
  • 在新建bitmap之前,先对Canvas进行剪裁,在Canvas内部的画布被剪裁后,利用saveLayer()函数生成的画布大小与剪裁后的画布大小相同;而且再利canvas.restore()函数进行恢复时,只会把saveLayer()函数新建画布的内容叠加,而不会将剪裁的Canvas恢复(API23失效)
  • 在与CLIP_SAVE_FLAG标识共用时,以CLIP_SAVE_FLAG为主
flag之ALL_SAVE_FLAG:
  • 它是所有标识的公共集合
  • 对于save()来说,ALL_SAVE_FLAG = MATRIX_SAVE_FLAG|CLIP_SAVE_FLAG,即保存位置信息和裁剪信息,因为save(int flag)函数只能使用MATRIX_SAVE_FLAG和CLIP_SAVE_FLAG
  • 对于saveLayer()来说, ALL_SAVE_FLAG = MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG | HAS_ALPHA_LAYER_SAVE_FLAG,即保存的位置信息和裁剪信息,新建画布在与上一层画布合成时, 不清空原画布的内容

注意:上述的Flag除了ALL_SAVE_FLAG以外的所有标识在API26以后已经废弃,在低版本中仍然可以使用


标签:Canvas,saveLayer,canvas,画布,FLAG,图层,SAVE
From: https://blog.51cto.com/u_13987312/5992407

相关文章

  • C#下ArcSDE(Oracle)图层数据变化监控实现
    因业务需要对ArcSDE中单个图层的变化进行监控,在出现图形插入、删除,图形和属性修改时及时获取到发生变化的要素。研究了一下可以通过C#进行监控。核心代码如下:stringsq......
  • canvas 源码汇总
    Source/core/html/canvasContainscanvas-relatedsupportclasses,including:thebaseclassforallCanvasRenderingContextthebaseclassforallelementsthat......
  • canvas德卡斯特里奥算法构造贝塞尔曲线可视化实现
    前言在现代js教程中看到通过德卡斯特里奥算法构造贝塞尔曲线的demo,觉得很有意思,尝试自己写一下目标效果如下吐槽一下,我看到文章底部才发现原来这里的demo是svg做的开......
  • 微信小程序canvas验证码生成及使用
    先看效果:  wxml:<canvasclass="v-code"bindtap="changeImg"style="width:100px;height:40px;"canvas-id="canvas"></canvas>js:constMCAP=require('.......
  • Unity2019学习:常用功能--Canvas画布
    Canvas(画布)游戏对象是其他UnityUI的基础,其他的UnityUI必须是Canvas(画布)游戏对象的下级游戏对象。当UI内容发生变化的时候,是以画布为单位进行重绘,合理的将内容分配到不同的......
  • canvasToImage报错:_canvas2image2.default.convertToImage is not a function
    vue2+js项目,某个屏幕截图功能,报错:代码中用到的importcanvasToImagefrom'canvas2image';打印canvasToImage发现是{},那么canvasToImage.convertToImage自然会报错。......
  • html2canvas页面生成截图
    什么是html2canvs?html2canvas 的作用就是允许让我们直接在用户浏览器上拍摄网页或其部分的“截图”。它的屏幕截图是基于 DOM 的,因此可能不会100%精确到真实的表......
  • echarts实现世界地图,解决series-map和geo同时使用导致在地图上缩放图层会重叠的问题
    主要使用到的配置:geoIndex//将坐标与值对应并反映在地图上convertData(data){varres=[];varthat=thisfor(vari=0;i<data.length;i++)......
  • GIMP选择,GIMP画布大小,GIMP图层
    基本概念1. 画布2. 图层你只能操作一个图层——就是你选中的。就看起来所有的图像都在一起,但是不同的图层中的图像是不同,不能操作没有选中的图层。对于选择......
  • Django视图层
    目录Django视图层一、视图层之必会三板斧二、JsonResponse对象三、request对象四、视图层之FBV与CBV五、CBV源码剖析六、虚拟环境Django视图层一、视图层之必会三板斧用......