X

Canvasの状態を保存/復帰させる

View#onDrawメソッドの表示処理ではCanvasを用いて描画を行います。複数のBitmapやオブジェクトを表示したい場合は描画ごとに表示位置を計算する必要があります。Canvasの状態を保存する主な目的は描画処理の簡略化です。描画位置がわかりやすくなるほか、任意のタイミングでCanvasの状態を復帰させられるメリットがあります。プログラミング上でのテクニックとしてどうぞ。

  • Canvas#save() 状態を保存する
  • Canvas#restore() 保存した状態へ復帰する

Canvas#save/restoreメソッドで保存できるのは回転、平行移動、図形のゆがみなどを表現するmatrix、表示範囲を指定するclip、の2種類の情報です。アプリケーションのスクリーンショットを取得するように1ピクセルの色情報単位で保存・復帰することはできませんので注意してください。

サンプルコード

以下のソースコードを実行すると画像のように直立したマスコット(緑)と傾いたマスコット(赤)が重なって描画されます。

        @Override
        protected void onDraw(Canvas canvas) {
            canvas.drawColor(Color.WHITE);

            canvas.drawBitmap(mAndroidGreen, 0, 0, mPaint);
            //現在の状態を覚える
            canvas.save();

            //一時的に移動
            canvas.rotate(45);
            canvas.drawBitmap(mAndroidRed, 0, 0, mPaint);

            //移動した分を元に戻す(-45)
            canvas.restore();
        }

6行目で状態を保存します。45度Canvasを回転させてマスコット(赤)を描画した後、13行目で状態を復帰させています。


図示することで、わかりやすく説明できます。図中の1~4の順番でソースコードを実行、描画しています。

  1. Canvas#saveメソッドで現在のCanvas状態(行列matrixと表示範囲clip)を保存
  2. Canvasを45度回転させる
  3. 回転後のCanvasに対してマスコット(赤)をdraw
  4. Canvas#restoreメソッドで元のmatrixと表示範囲に復帰

サンプルコードの全体の解説はつづきから。

CanvasActivity.java

public class CanvasActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(new CustomView(this));
    }

    private static class CustomView extends View {

        private Paint mPaint;

        private Bitmap mAndroidGreen;
        private Bitmap mAndroidRed;

        public CustomView(Context context) {
            super(context);
            setFocusable(true);

            mPaint = new Paint();

            Resources res = getResources();
            mAndroidGreen = BitmapFactory.decodeResource(res, R.drawable.android_green);
            mAndroidRed = BitmapFactory.decodeResource(res, R.drawable.android_red);
        }

        @Override
        protected void onDraw(Canvas canvas) {
            canvas.drawColor(Color.WHITE);

            canvas.drawBitmap(mAndroidGreen, 0, 0, mPaint);
            //現在の状態を覚える
            canvas.save();

            //一時的に移動
            canvas.rotate(45);
            canvas.drawBitmap(mAndroidRed, 0, 0, mPaint);

            //移動した分を元に戻す(-45)
            canvas.restore();
        }
    }
}

CanvasActivityはCustomViewを内部クラスに持ち、CustomViewのコンストラクタでリソースを読み込みます。
View#onDrawメソッドでCanvas#save, Canvas#restoreメソッドを利用して画像描画を行っています。

mhidaka: Software Engineerだよ。DroidKaigi Organizer / Androidと組込とRe:VIEW。techbooster主宰。mhidaka's writings http://booklog.jp/users/mhidaka 技術書典! http://techbookfest.org