2015年3月22日日曜日

Canvasクラスを制すものは描画を制す

AndroidはViewを描写をするときonDraw(Canvas canvas)メソッドで行っている
この引数のCanvasクラスは描画するための最小単位のクラスで、こいつでテキストだしたり、画像出したりしてる。android1.0から存在する大先輩クラス
今ではほとんどCanvasを意識せずViewの組み合わせによりUI構築を行うが、結局は各ViewのonDraw()で描写してるだけに過ぎない。ゆえにImageView、TextView、ListViewなどのViewを継承してるクラスのonDraw()をオーバーライドさせてやれば何でも描画できる!
てことでonDraw時のCanvasを制御する方法をまとめる
 文字の逆さ表示(TextViewのOverride)
やり方はCanvasを回転させて逆さにする。
Canvas# rotate()メソッドに回転方向、回転軸x、yを引数にして回転させる
回転軸は設定しないと、Viewの左上が回転軸になる。Viewの中心で回転させるので、横幅、縦幅の半分が回転軸
/** 逆向き表示TextView */
TextView textView1 = new TextView(this) {
    @Override
    public void onDraw(Canvas canvas) {
        canvas.save();
        canvas.rotate(180, getWidth() / 2, getHeight() / 2);
        super.onDraw(canvas);
        canvas.restore();
    }
};
 文字の反転(TextViewのOverride)
やり方はCanvasの倍率を変更するメソッドで倍率をx軸を-1倍にする。
そうすると、X軸に対し、線対称に表示される
/** 反転表示TextView */
TextView textView4 = new TextView(this) {
    @Override
    public void onDraw(Canvas canvas) {
        canvas.save();
        canvas.scale(-1, 1);
        canvas.translate(-getWidth(), 0);
        super.onDraw(canvas);
        canvas.restore();
    }
};
 影付き文字(TextViewのOverride)
影付けるにはCanvasの文字を描写するメソッドを使い、少しずれた位置に表示文字色より、薄い色で文字を描く
/** 影付きTextView */
TextView textView2 = new TextView(this) {
    Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
    @Override
    public void onDraw(Canvas canvas) {
        canvas.save();
        // 影の部分を先に描いてその上にほんとの文字を描く
        // 色の設定。本物の色を取ってきて、RGBに加算して色を足す
        p.setColor(getTextColors().getDefaultColor() | 0x00AFAFAF);
        // 文字のサイズを合わせる
        p.setTextSize(getTextSize());
        // 表示文字を合わせる
        String text = getText().toString();
        // 文字の表示位置調整。文字の高さ、マージンとか計算
        FontMetrics fm = p.getFontMetrics();
        float size = (fm.descent - fm.ascent);
        float margin = (getHeight() - size) / 2;
        canvas.drawText(text, 0, margin + getTextSize(), p);
        // 表示位置のずれ具合調整。だいたい5とか10くらい
        int dx = 5;
        canvas.drawText(text, 0 + dx, margin + getTextSize() + dx, p);
        canvas.restore();
        // 通常描写
        super.onDraw(canvas);
    }
};
 スクロールアニメーション(TextViewのOverride)
Handler使って描画時間を調整しつつ、Canvasを平行移動させていくことで文字をずらしていく。
Handlerでスレッド止めたりするのキューたまりすぎないか心配なので、Threadとかで時間管理した方がいい気がする
/** スクロールアニメーションTextView. */
TextView textView3 = new TextView(this) {
    Point point = new Point();
    Handler handler = new Handler();
    Runnable runnable = new Runnable() { public void run() {
            // 10m秒このスレッドの時間を止める。その後強制描写メソッドで、onDraw()を呼ぶ
            try {Thread.sleep(10);} catch (InterruptedException e) {}
            invalidate();}
    };
    @Override
    public void onDraw(Canvas canvas) {
        canvas.save();
        // 結構ややこしい計算だけど、幅の2倍移動するので、移動式がこんな感じ
        canvas.translate(point.x + getWidth(), 0);
        super.onDraw(canvas);
        canvas.restore();
        // 座標を3ずらして表示。表示幅の2倍より大きくなったらリセット
        point.x = (point.x -3) % (getWidth() * 2);
        handler.post(runnable);
    }
};
 角度を変えた画像の重ね合わせ(ImageViewのOverride)
この画像を回転させながら重ね合わせて、扇風機の羽を作る
文字反転と同じようにCanvasをView中心で回転させて、onDraw()を何度も呼ぶ。
/** 重ね合わせImageView. */
ImageView imageView = new ImageView(this) {
    @Override
    public void onDraw(Canvas canvas) {
        canvas.save();
        // 回転軸の決定
        PointF axis = new PointF(getWidth() / 2, getHeight() / 2);
        super.onDraw(canvas);
        canvas.rotate(90, axis.x, axis.y);
        super.onDraw(canvas);
        canvas.rotate(180, axis.x, axis.y);
        super.onDraw(canvas);
        canvas.rotate(270, axis.x, axis.y);
        super.onDraw(canvas);
        canvas.restore();
    }
};
こんな感じで簡単にViewの編集が行える

0 件のコメント:

コメントを投稿