Canvasに図形を描画する|Android開発
androidでCanvas
へ図形や文字を描画する方法です。
SurfaceView
を継承したビューを作成し、onDraw()
がコールされた時などにCanvas
へ描画を行います。
描画用クラスのサンプル
public class PaintView extends SurfaceView implements SurfaceHolder.Callback {
private static final String TAG = "PaintView";
private int mCurrentWidth = 0;
private int mCurrentHeight = 0;
private SurfaceHolder mHolder;
public PaintView(Context context) {
this(context, null);
}
public PaintView(Context context, AttributeSet attrs) {
super(context, attrs);
mHolder = getHolder();
mHolder.addCallback(this);
setWillNotDraw(false);
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.i(TAG, "surfaceCreated");
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.i(TAG, "surfaceChanged");
if (mCurrentWidth == width && mCurrentHeight == height) {
return;
}
mCurrentWidth = width;
mCurrentHeight = height;
doDraw();
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.i(TAG, "surfaceDestroyed");
}
private void doDraw() {
Canvas canvas = mHolder.lockCanvas();
if (canvas == null) {
Log.e(TAG, "SurfaceHolder.lockCanvas() is null.");
return;
}
doDraw(canvas);
mHolder.unlockCanvasAndPost(canvas);
}
/**
* 実際の描画処理.
*/
private void doDraw(Canvas canvas) {
if (mCurrentWidth == 0 || mCurrentHeight == 0) {
return;
}
Paint paint = new Paint();
// 背景を塗り潰す.
canvas.drawColor(Color.WHITE);
// 描画処理.
}
@Override
public void onDraw(Canvas canvas) {
Log.i(TAG, "onDraw");
doDraw(canvas);
}
}
setWillNotDraw()
true
を設定するとonDraw()
が呼ばれなくなります。
Canvas の描画メソッド
Canvas
クラスの描画メソッドとサンプルです。上記サンプルのdoDraw()
の中で使用します。
背景を塗り潰す
canvas.drawColor(Color.BLUE);
線を引く
引数はstartX, startY, stopX, stopYの順で(startX, startY)から(stopX, stopY)に線を引きます。
canvas.drawLine(0.f, 0.f, mCurrentWidth, mCurrentHeight, paint);
複数の線を引く
第1引数は座標の配列。個数は4の倍数でx1, y2, x2, y2の順で(x1, y1)から(x2, y2)に線を引きます。以降、このセットの繰り返し。
配列の要素数を4個にして1本だけ線を引くことも可能です。
canvas.drawLines(new float[]{
0.f, 0.f, mCurrentWidth / 2.f, mCurrentHeight, // 1本目の線の座標.
mCurrentWidth / 2.f, mCurrentHeight, mCurrentWidth / 2.f, 0.f, // 2本目の線の座標.
}, paint);
円を描画する
引数は円の中心座標x, y, 半径の長さの順。
canvas.drawCircle(mCurrentWidth / 2.f, mCurrentHeight / 2.f, mCurrentHeight / 2.f, paint);
楕円を描画する
指定した矩形に隣接する楕円を描画します。
canvas.drawOval(new RectF(0.f, 0.f, mCurrentWidth / 2.f, mCurrentHeight), paint);
四角形を描画する.
canvas.drawRect(new RectF(0.f, 0.f, mCurrentWidth / 2.f, mCurrentHeight), paint);
Paint の設定
描画幅を変更する
paint.setStrokeWidth(5);
描画色を変更する
paint.setColor(Color.RED);
ARGBで指定する場合。
paint.setColor(0xFFFF0000);
円や矩形を塗り潰さないようにする
setStyle()
でPaint.Style.STROKE
を指定すると、円や矩形の描画で枠線のみを描画します。
paint.setStyle(Paint.Style.STROKE);
文字列描画の文字サイズ
paint.setTextSize(20);
文字列の描画
文字列描画の座標は左、下(ベースライン)を指定します。
measureText()
で文字列描画時の幅を取得できます。
// 文字列描画用の Paint インスタンス.
Paint labelPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
labelPaint.setTextSize(20);
labelPaint.setColor(Color.BLACK);
float labelWidth = labelPaint.measureText("blue days.");
canvas.drawText("blue days.", mCurrentWidth - labelWidth, 50, labelPaint);
getTextBounds()
で文字列描画時の矩形を取得できます。
// 文字列描画用の Paint インスタンス.
Paint labelPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
labelPaint.setTextSize(20);
labelPaint.setColor(Color.BLACK);
Rect rect = new Rect();
labelPaint.getTextBounds("BLUE DAYS.", 0, "BLUE DAYS.".length(), rect);
canvas.drawText("BLUE DAYS.", mCurrentWidth - rect.width(), rect.height(), labelPaint);
paint.setColor(Color.RED);
canvas.drawLine(mCurrentWidth - rect.width(), rect.height(), mCurrentWidth, rect.height(), paint);
文字列を回転して描画する
文字列を縦方向に描画したい場合など。
Canvas.save()
で現在のキャンバス描画情報を保存するCanvas.rotate()
でキャンバスを回転させる
Canvas.save()~Canvas.restore()
までの描画が回転する- 描画処理を行う(座標は回転前の値)
Canvas.restore()
で保存した描画情報を戻す
描画処理の座標は
rotate()
で指定した座標を中心に回転することを考えて逆算する。// 文字列描画用の Paint インスタンス.
Paint labelPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
labelPaint.setTextSize(20);
labelPaint.setColor(Color.BLACK);
// ビューの中心座標で回転させる.
float cx = getWidth() / 2.f;
float cy = getHeight() / 2.f;
paint.setColor(Color.RED);
canvas.drawLines(new float[] {
0.f, cy, mCurrentWidth, cy,
cx, 0.f, cx, mCurrentHeight,
}, paint);
canvas.save();
Rect rect = new Rect();
labelPaint.getTextBounds("rotate 90.", 0, "rotate 90.".length(), rect);
canvas.rotate(90, cx, cy);
paint.setColor(Color.CYAN);
canvas.drawRect(new RectF(cx - rect.width(), cy - rect.height(), cx, cy), paint);
canvas.drawText("rotate 90.", cx - rect.width(), cy, labelPaint);
canvas.restore();