【Android】Canvasを使ってルーレットを作る① - CanvasにdrawArcでルーレットを描画する -

android.graphics.CanvasはAPI Level 1の頃からある最古のAPIです。

これを利用してルーレットアプリを作るまでを記事にしたいと思います。

何回かに分けるので今回はViewを継承したRouletteViewを作り、onDraw()で描画するところまでです。

実装

Viewクラスを継承したRouletteViewクラス.コンストラクタ

コンストラクタ

public RouletteView(Context context, int num) {
    super(context);
    paint = new Paint();
    paint.setAntiAlias(true);

    textPaint = new Paint(Color.DKGRAY);
    textPaint.setTextSize(60);
    textPaint.setAntiAlias(true);

    pos = 0;
    this.num = num;
    angle = 360 / num;
}

パネル用のPaintオブジェクトとテキスト用のPaintオブジェクトを生成します。

setAntiAliasにtrueを設定しておくと文字や線が滑らかに描画されます。

numはパネルの数、angleはパネル1個の角度をそれぞれセットします。

onDraw()メソッド

初回時の処理

if(init == 0) {
    if(xc == 0.0f) xc = canvas.getWidth() / 2;
    if(yc == 0.0f) yc = canvas.getHeight() / 2;

    if(rectF == null) rectF = new RectF(0.0f, yc - xc, canvas.getWidth(), yc + xc);

    init = 1;
}

これは初回描画時の処理です。

Canvasの中心点とRectFオブジェクトをMainActivityのメンバ変数にセットし、次回のonDrawからは再利用するようにしています。

rectFはCanvasの横幅にあわせた正方形で生成し、この中にルーレットのパネル(弧)を描画します。

パネルの描画

for (int i = 0; i < num; i++) {
    paint.setColor(colors[i]);
    canvas.drawArc(rectF, (i * angle), angle, true, paint);
}

ここではパネルの描画処理を行っています。

パネル用のカラーをセットし、drawArc()メソッドによって弧の描画を行います。

drawArcの第2引数によってそれぞれのパネルの描画位置が決まります。

6枚のパネルだったら1枚目が0、2枚目が60、3枚目が120といった感じです。

テキストの表示

for (int j = 0; j < num; j++) {
    int intTextAngle;
    if(j == 0) {
        intTextAngle = angle / 2;
    } else{
        intTextAngle = angle;
    }
    canvas.rotate(intTextAngle, xc, yc);
    canvas.drawText(testStrings[j], xc + 100, yc + 20, textPaint);
}

描画処理の最後はパネルの上に表示するテキストの描画処理です。個人的にここが一番嵌りました。

drawText()メソッドでテキストの描画を行いますが、drawTextは角度を指定できないためCanvasをrotate()メソッドで回転させます。

パネルの中心にテキストを持っていきたいので、最初だけパネルの半分だけ回転させて、2回目以降はパネルの角度だけ移動させています。

drawTextの xc + 100, yc + 20 は文字列がパネルの中心に来るよう微調整です。

ここは端末によって画面サイズが違うので相対で動的に取得した方が良さそうです。

最終的なソースコード

MainActivity.java [クリックで表示]

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {

    private RouletteView rouletteView;

    private int[] colors = {
            Color.argb(255, 255, 255, 128),
            Color.argb(255, 255, 128, 255),
            Color.argb(255, 128, 255, 255),
            Color.argb(255, 128, 128, 255),
            Color.argb(255, 128, 255, 128),
            Color.argb(255, 255, 128, 128),
    };

    private String[] testStrings = {
            "カレーライス",
            "肉じゃが",
            "オムレツ",
            "マーボー豆腐",
            "鳥のから揚げ",
            "ビーフシチュー",
    };

    // Canvas 中心点
    private float xc = 0.0f;
    private float yc = 0.0f;

    private RectF rectF = null;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //setContentView(R.layout.activity_main);

        init();
    }

    private void init() {
        // ルーレットView作成
        rouletteView = new RouletteView(this, 6);
        setContentView(rouletteView);
    }

    class RouletteView extends View {

        Paint paint;

        Paint textPaint;

        int angle;

        int num;

        int init = 0;

        public RouletteView(Context context, int num) {
            super(context);
            paint = new Paint();
            paint.setAntiAlias(true);

            textPaint = new Paint(Color.DKGRAY);
            textPaint.setTextSize(60);
            textPaint.setAntiAlias(true);

            this.num = num;
            angle = 360 / num;
        }

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

            if(init == 0) {
                // Canvas 中心点
                if(xc == 0.0f) xc = canvas.getWidth() / 2;
                if(yc == 0.0f) yc = canvas.getHeight() / 2;

                // 画面の中心から横幅に合わせた正方形を作る
                if(rectF == null) rectF = new RectF(0.0f, yc - xc, canvas.getWidth(), yc + xc);

                init = 1;
            }

            // パネルの描画
            for (int i = 0; i < num; i++) {
                paint.setColor(colors[i]);
                canvas.drawArc(rectF, (i * angle), angle, true, paint);
            }

            // テキストの描画
            for (int j = 0; j < num; j++) {
                int intTextAngle;
                if(j == 0) {
                    intTextAngle = angle / 2;
                } else{
                    intTextAngle = angle;
                }
                canvas.rotate(intTextAngle, xc, yc);
                canvas.drawText(testStrings[j], xc + 100, yc + 20, textPaint);
            }
        }
    }
}

実行結果

次回はこのCanvasにアニメーションをつけて動かしてみたいと思います。

コメント

このブログの人気の投稿

docker-compose up で proxyconnect tcp: dial tcp: lookup proxy.example.com: no such host

docker-compose で起動したweb、MySQLに接続できない事象

【PHP】PHP_CodeSnifferを使う(コーディングルールのカスタマイズ)