【Android UI】Canvas 画布 ③ ( Canvas 图层栈 | Canvas#saveLayer() 新建图层 | Canvas 状态栈保存信息标志位 )

2023-03-30 16:04:23 浏览数 (2)

文章目录

  • 一、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;

0 人点赞