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

Posted 韩曙亮

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android UICanvas 画布 ③ ( Canvas 图层栈 | 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() 函数原型如下 :

    /**
     * 其行为与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 3 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 , 一般情况下都设置保存所有信息 ;

    /** @hide */
    @IntDef(flag = true,
            value = 
                    ALL_SAVE_FLAG
            )
    @Retention(RetentionPolicy.SOURCE)
    public @interface Saveflags 

3 3 3 个参数的 Canvas#saveLayer() 函数原型如下 :

    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);
    

保存形式状态位原型 :

    // 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;

以上是关于Android UICanvas 画布 ③ ( Canvas 图层栈 | Canvas#saveLayer() 新建图层 | Canvas 状态栈保存信息标志位 )的主要内容,如果未能解决你的问题,请参考以下文章

Android UICanvas 画布 ② ( Canvas 状态栈 | Canvas 状态栈出栈到指定层级 )

Android UICanvas 画布 ⑦ ( Canvas 绘制显示区域 | Canvas 绘制矩形源码分析 )

Android UICanvas 画布 ⑤ ( Canvas 坐标系 | Canvas 绘图坐标系变换示例 )

Android UICanvas 画布 ⑥ ( Canvas 绘图源码分析 | ViewRootImpl#draw 方法源码 | ViewRootImpl#drawSoftware 方法源码 )

Android UICanvas 画布 ④ ( Canvas 坐标系 | Canvas 自身坐标系 | Canvas 绘图坐标系 )

Android UICanvas 画布 ⑧ ( Canvas 绘图坐标系 2x2 矩阵 | Canvas 绘图坐标系 3x3 操作矩阵 )