文章目录
- 一、Canvas#saveLayer() 新建图层
- 二、Canvas 状态栈保存信息标志位
Canvas 状态保存机制 中 , 存在两个栈结构 , 分别是 状态栈 和 图层栈 ;
其中 图层栈 又称为 Layer 栈 ;
一、Canvas#saveLayer() 新建图层
Canvas 画布类 , 提供了 Canvas#saveLayer()函数 , 用于 创建 新的图层 ;
在自定义组件的 onDraw() 方法中 , 调用 Canvas#saveLayer() 函数 新建图层 完成后 , 后续绘图都是在 新建的图层 中绘制的 , 之前已经绘制的内容不会受到影响 ;
新建图层 只负责将当前图层区域绘制 , 不会干扰其他图层的绘制 ;
Canvas#saveLayer() 函数 相当于创建了一个透明图层 , 之后的绘图操作 , 都在透明图层中执行的 ;
Layer 图层 其在底层也是 由 状态栈 进行保存的 , Canvas#saveLayer() 函数 返回一个 int 类型的返回值 , 这个值是当前的图层对应的 状态栈 索引值 ;
之后调用 Canvas#restoreToCount() 函数 , 传入上述 Canvas#saveLayer() 函数的 int 类型返回值 , 即可使 状态栈 出栈到 该图层对应的 元素 , 即该元素置为栈顶位置 ;
状态栈 中 , 保存的不只是坐标系信息 , 还包括 矩阵信息 , 大小信息 , 图层透明度信息 等 ;
Canvas#saveLayer() 函数原型如下 :
代码语言:javascript复制 /**
* 其行为与save()相同,但除此之外,它还分配和
* 将图形重定向到屏幕外渲染目标。
* 注意:这种方法非常昂贵,
* 导致包含内容的呈现成本增加一倍以上。避免
* 在可能的情况下使用此方法,而不是使用
* {@link android.view.view在视图上查看#LAYER_TYPE_HARDWARE HARDWARE LAYER}
* 应用xfermode、颜色过滤器或alpha,因为它将执行很多操作
* 比这种方法更好。
* <p>
* 所有图形调用都指向新分配的屏幕外渲染目标。
* 只有在对restore()进行平衡调用时,才是屏幕外的
* 缓冲区拉回到画布的当前目标(可能是前一个
* 层(如果这些调用是嵌套的)。
* <p>
* 绘制的属性{@link Paint#getAlpha()alpha},
* {@link Paint#getXfermode()Xfermode},和
* 当
* 调用restore()时,屏幕外渲染目标会被拉回。
*
* @param bounds 可能为空。屏幕外渲染目标需要的最大大小(在局部坐标中)
* @param paint 这将被复制,并在调用restore()时应用于屏幕外
* @return 要传递给restoreToccount()以平衡此save()的值
*/
public int saveLayer(@android.annotation.Nullable RectF bounds, @android.annotation.Nullable Paint paint) {
return saveLayer(bounds, paint, ALL_SAVE_FLAG);
}
二、Canvas 状态栈保存信息标志位
Canvas#saveLayer() 函数 , 还有一个 3 个参数的多态方法 , 第三个参数就是 状态栈 保存形式 状态位 ;
- MATRIX_SAVE_FLAG 状态位 : 只保存 图层 中的 Martrix 矩阵信息 ;
- CLIP_SAVE_FLAG 状态位 : 只保存大小 信息 ;
- HAS_ALPHA_LAYER_SAVE_FLAG 状态位 : 只保存透明度信息 ;
- FULL_COLOR_LAYER_SAVE_FLAG 状态位 : 保存完整的颜色信息 ;
- ALL_SAVE_FLAG 状态位 : 保存所有信息 ;
Canvas 中有如下默认注解 , 该标志位默认为 ALL_SAVE_FLAG , 一般情况下都设置保存所有信息 ;
代码语言:javascript复制 /** @hide */
@IntDef(flag = true,
value = {
ALL_SAVE_FLAG
})
@Retention(RetentionPolicy.SOURCE)
public @interface Saveflags {}
3 个参数的 Canvas#saveLayer() 函数原型如下 :
代码语言:javascript复制 public int saveLayer(@Nullable RectF bounds, @Nullable Paint paint, @Saveflags int saveFlags) {
if (bounds == null) {
bounds = new RectF(getClipBounds());
}
checkValidSaveFlags(saveFlags);
return saveLayer(bounds.left, bounds.top, bounds.right, bounds.bottom, paint,
ALL_SAVE_FLAG);
}
保存形式状态位原型 :
代码语言:javascript复制 // SAVE_FLAG 常数必须与下面定义的值匹配
/** @hide */
@IntDef(flag = true,
value = {
ALL_SAVE_FLAG
})
@Retention(RetentionPolicy.SOURCE)
public @interface Saveflags {}
/**
* 调用Restore()时还原当前矩阵。
* @removed
* @deprecated 使用{@link#save()}、{@link#saveLayer(RectF,Paint)}或
* {@link#saveLayerAlpha(RectF,int)}。For saveLayer()调用矩阵
* 始终为{@link#isHardwareAccelerated()硬件加速}还原
* canvas和as的API级别{@value Build.VERSION_代码#O},这是默认值
* 所有画布类型的行为。
*/
public static final int MATRIX_SAVE_FLAG = 0x01;
/**
* 调用Restore()时还原当前剪辑。
*
* @removed
* @deprecated 使用{@link#save()}、{@link#saveLayer(RectF,Paint)}或
* {@link#saveLayerAlpha(RectF,int)}。For saveLayer()调用剪辑
* 始终为{@link#isHardwareAccelerated()硬件加速}还原
* canvas和as的API级别{@value Build.VERSION_代码#O},这是默认值
* 所有画布类型的行为。
*/
public static final int CLIP_SAVE_FLAG = 0x02;
/**
* 该层需要每像素alpha通道。
*
* @removed
* @deprecated 忽略此标志。使用{@link#saveLayer(RectF,Paint)}的无标志版本
* {@link#saveLayerAlpha(RectF,int)}。
*/
public static final int HAS_ALPHA_LAYER_SAVE_FLAG = 0x04;
/**
* 该层要求每个颜色通道具有完整的8位精度。
*
* @removed
* @deprecated 忽略此标志。使用{@link#saveLayer(RectF,Paint)}的无标志版本
* {@link#saveLayerAlpha(RectF,int)}。
*/
public static final int FULL_COLOR_LAYER_SAVE_FLAG = 0x08;
/**
* 将绘图剪切到屏幕外层的边界,忽略此操作将产生后果。
* 注意:强烈建议不要
* 对于任何调用saveLayer()</code>和
* <code>saveLayerAlpha()</code>变体。一般不通过此标志
* 触发硬件加速渲染的极低性能。
*
* @removed
* @deprecated 此标志会导致性能较差,使用
* 具有不同剪辑的单个图层或多个绘制命令。
*
*/
public static final int CLIP_TO_LAYER_SAVE_FLAG = 0x10;
/**
* 调用Restore()时还原所有内容(标准保存标志)。
* 注:出于性能原因
* 强烈建议将这一整套标志传递给任何
* 调用saveLayer()和saveLayerAlpha()
* 变体。
*
* 注意:接受此标志的所有方法
* 具有等同于传递此标志的无标志版本。
*/
public static final int ALL_SAVE_FLAG = 0x1F;