09.4 精通自定义 View 之 Canvas 与图层——恢复画布

返回自定义 View 目录

恢复画布有两个函数:restore() 和 restoreToCount(int count)。
其中,restore() 函数的作用就是把回退栈中的最上层画布状态出栈,恢复画布状态。在 1.5.2 节中已经详细地说明了 restore() 函数的用法,这里就不再赘述了。

9.4.1 restoreToCount(int count)

在 save()、saveLayer()、saveLayerAlpha() 函数保存画布后,都会返回一个 ID 值,这个 ID 值表示当前保存的画布信息的栈层索引(从 0 开始)。比如,保存在第三层,则返回 2。

而 restoreToCount() 函数的声明如下:

1
public void restoreToCount(int saveCount);

它表示一直退栈,一直把指定索引的画布信息退出来,之后的栈最上层的画布信息将作为最新的画布。比如,我们开始的栈已经有两层,然后调用如下代码:

1
2
3
int id = canvas.saveLayer(0, 0, etWidth(), getHeight(), mPaint,
Canvas.ALL_SAVE_FLAG);
canvas.restoreToCount(id);

调用 canvas.saveLayer() 函数后,新保存的画布放在了第三层,返回的 ID 的值是对应的索引,即 2。而 canvas.restoreToCount(id); 则表示一直退栈,直到把索引为 2 的栈层给退出去,留下来的栈顶层信息将作为最新的画布。

下面我们举个例子来看下。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class TestView extends View {
private Paint mPaint;
private String TAG = "XIAN";
public TestView(Context context, AttributeSet attrs) {
super(context, attrs);
mPaint = new Paint();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int id1 = canvas.save();
canvas.clipRect(0, 0, 800, 800);
canvas.drawColor(Color.RED);
Log.d(TAG, "count:" + canvas.getSaveCount() + " id1:" + id1);
int id2 = canvas.saveLayer(0, 0, getWidth(), getHeight(), mPaint, Canvas.ALL_SAVE_FLAG);
canvas.clipRect(100, 100, 700, 700);
canvas.drawColor(Color.GREEN);
Log.d(TAG, "count:" + canvas.getSaveCount() + " id2:" + id2);
int id3 = canvas.saveLayerAlpha(0, 0, getWidth(), getHeight(), 0xF0, Canvas.ALL_SAVE_FLAG);
canvas.clipRect(200, 200, 600, 600);
canvas.drawColor(Color.YELLOW);
Log.d(TAG, "count:" + canvas.getSaveCount() + " id3:" + id3);
int id4 = canvas.save();
canvas.clipRect(300, 300, 500, 500);
canvas.drawColor(Color.BLUE);
Log.d(TAG, "count:" + canvas.getSaveCount() + " id4:" + id4);
}
}

在 onDraw() 函数中,连续对 Canvas 进行裁剪,并且在裁剪后在当前画布上涂一层不同的颜色,然后把当前栈的层数和最高层的索引打印出来。

效果图

日志

在整段代码的最后添加 canvas.restoreToCount(id3);,然后把整块画布涂成灰色。

1
2
3
4
5
6
7
8
9
10
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
...
canvas.restoreToCount(id3);
canvas.drawColor(Color.GRAY);
Log.d(TAG, "count:" + canvas.getSaveCount());
}

效果图

日志

从代码中可以看出,在调用 canvas.restoreToCount(id3) 函数后,将恢复到生成 id3 之前的画布状态,即是 (100, 100, 700, 700)。

9.4.2 restore() 和 restoreToCount(int count) 的关系

这两个函数针对的是同一个栈,所以完全可以通用。不同的是,restore() 函数默认将栈顶内容退出还原画布;而 restoreToCount(int count) 函数则是一直退栈,直到把指定索引的画布信息退出来,之后的栈最上层的画布信息将作为最新的画布。

结论:

  • restore() 的含义是把回退栈中的最上层画布状态出栈,恢复画布状态。restoreToCount(int count) 的含义是一直退栈,直到把指定索引的画布信息退出来,将此之前的所有动作都恢复。
  • 无论哪种 save 函数、哪个 FLAG,保存画布时使用的都是同一个栈。
  • restore() 与 restoreToCount(int count) 针对的都是同一个栈,所以完全可以通用。

男人喜欢球.gif