📚

ビュー描画の基礎(View / Canvas / Paint)

2022/11/23に公開約11,300字

はじめに

View・Canvas・Paintの簡単な使用例を備忘録として記述しています。

開発環境

Android 10
AndroidStudio Bumblebee
macOS 12.3
minSdk 28
targetSdk 31
実行端末 Pixel3a

参考資料

View
https://developer.android.com/reference/android/view/View
Canvas
https://developer.android.com/reference/android/graphics/Canvas
Paint
https://developer.android.com/reference/android/graphics/Paint

ビューとは

Android開発で使用される様々なビュー(Button,EditTextなど)は、元を辿れば、Viewクラスを継承したView派生クラスです。
独自にビューを作成したい場合はViewクラスを継承し、独自の描画処理を実装することで実現できる。

Viewクラス : ビューの描画に関する基本的な機能だけを提供するクラス

android.view.View(全てのビューのスーパークラス)
|
|____ android.widget.TextView
|             |____ android.widget.Button
|             |____ android.widget.EditText
|             |____ ...
|____ ...
|
|____ android.view.ViewGroup
              |____ android.widget.FrameLayout
              |____ android.widget.LinerLayout
              |____ ...

カスタムビューを描く

Java側

SampleView.java
public class SampleView extends View {
    private Paint paint; ・・・①

    public SampleView(Context context) {
        super(context);
    }

    public SampleView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        // スタイル準備
        paint = new Paint();
	// 色
        paint.setColor(Color.CYAN);
	// 線(点)の太さ
        paint.setStrokeWidth(100);
    }

    public SampleView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
	// 背景色
        canvas.drawColor(Color.WHITE);
	// drawPoint(X座標, Y座標, 描画スタイル)
        canvas.drawPoint(100.0f, 100.0f, paint);
    }
}

onDraw

Androidがビューを表示/更新する際に呼び出すメソッド。
具体的な描画処理はここに記述する。

onDrawメソッド
    /**
     * onDraw
     * @param canvas 描画に使用するキャンバス
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
	...
    }

xml側

activity.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <com.example.canvastestjava.custom_view.SampleView
        android:id="@+id/main_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
	
    <!-- 以下の書き方でも問題ない -->
    <view 
        class="com.example.canvastestjava.custom_view.SampleView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>

様々な図形

点の描画を行います。
各点の座標を少しずらし表示させてみたいと思います。

Java側

DotView.java
public class DotView extends View {
    private Paint paint;

    public DotView(Context context) {
        super(context);
    }

    public DotView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        paint = new Paint();
        paint.setColor(Color.CYAN);
        paint.setStrokeWidth(30);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.DKGRAY);
        // 30づつ座標をずらす
        float[] ps = {
                50, 100,  // 1個目 (x:50,  y:100)
                80, 130,  // 2個目 (x:80,  y:130)
                110, 160, // 3個目 (x:110, y:160)
                140, 190,  // 4個目 (x:140, y:190)
        };
        canvas.drawPoints(ps, paint);
    }
}

xml側

上記の書き方を参照

直線

直線の描画を行います。
先端の形状を指定することが可能です。

drawLine
https://developer.android.com/reference/android/graphics/Canvas#drawLine(float, float, float, float, android.graphics.Paint)

Java側

LineView.java
public class LineView extends View {
    private Paint buttPaint;
    private Paint roundPaint;
    private Paint squarePaint;

    public LineView(Context context) {
        super(context);
    }

    public LineView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        buttPaint = new Paint();
        roundPaint = new Paint();
        squarePaint = new Paint();

        buttPaint.setColor(Color.CYAN);
        roundPaint.setColor(Color.CYAN);
        squarePaint.setColor(Color.CYAN);

        buttPaint.setStrokeWidth(50);
        roundPaint.setStrokeWidth(50);
        squarePaint.setStrokeWidth(50);

        // Paint.Cap.BUTT   先端処理なし
        buttPaint.setStrokeCap(Paint.Cap.BUTT);
        // Paint.Cap.ROUND  先端を丸める
        roundPaint.setStrokeCap(Paint.Cap.ROUND);
        // Paint.Cap.SQUARE 先端を四角形にする
        squarePaint.setStrokeCap(Paint.Cap.SQUARE);
    }

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

        float[] buttPositions = {100.0f, 500.0f, 1000.0f, 500.0f};
        float[] roundPositions = {100.0f, 700.0f, 1000.0f, 700.0f};
        float[] squarePositions = {100.0f, 900.0f, 1000.0f, 900.0f};

        canvas.drawLine(
                buttPositions[0], // 開始点X座標
                buttPositions[1], // 開始点Y座標
                buttPositions[2], // 終了点X座標
                buttPositions[3], // 終了点Y座標
                buttPaint);
        canvas.drawLine(
                roundPositions[0], // 開始点X座標
                roundPositions[1], // 開始点Y座標
                roundPositions[2], // 終了点X座標
                roundPositions[3], // 終了点Y座標
                roundPaint);
        canvas.drawLine(
                squarePositions[0], // 開始点X座標
                squarePositions[1], // 開始点Y座標
                squarePositions[2], // 終了点X座標
                squarePositions[3], // 終了点Y座標
                squarePaint);
    }

先端の形状

列挙値 内容
Paint.Cap.BUTT 先端処理なし
Paint.Cap.ROUND 先端を丸める(終点を中心とした半円)
Paint.Cap.SQUARE 先端を四角形にする(終点を中心とした四角形)

xml側

上記の書き方を参照

折れ線

折れ線の描画を行います。

drawLines
https://developer.android.com/reference/android/graphics/Canvas#drawLines(float[], android.graphics.Paint)

Java側

LinesView.java
public class Lines extends View {
    private Paint paint;

    public Lines(Context context) {
        super(context);
    }

    public Lines(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        paint = new Paint();
        paint.setColor(Color.CYAN);
        paint.setStrokeWidth(10);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        float[] ps = {
                50, 100, 350, 350,  // (50, 100) ~ (350, 350)
                350, 350, 575, 100, // (350, 350) ~ (575, 100)
                575, 100, 720, 350, // (575, 100) ~ (720, 350)
                720, 350, 900, 100  // (720, 350) ~ (900, 100)
        };
        canvas.drawLines(ps, paint);
    }
}

xml側

上記の書き方を参照

矩形

矩形の描画を行います。

drawRect
https://developer.android.com/reference/android/graphics/Canvas#drawRect(float, float, float, float, android.graphics.Paint)

Java側

RectView.java
public class RectView extends View {
    private Paint fillPaint;
    private Paint fillAndStrokePaint;
    private Paint strokePaint;

    public RectView(Context context) {
        super(context);
    }

    public RectView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        fillPaint = new Paint();
        fillAndStrokePaint = new Paint();
        strokePaint = new Paint();

        fillPaint.setColor(Color.CYAN);
        fillAndStrokePaint.setColor(Color.CYAN);
        strokePaint.setColor(Color.RED);

        fillPaint.setStrokeWidth(20);
        fillAndStrokePaint.setStrokeWidth(20);
        strokePaint.setStrokeWidth(20);

        fillPaint.setStyle(Paint.Style.FILL);
        fillAndStrokePaint.setStyle(Paint.Style.FILL_AND_STROKE);
        strokePaint.setStyle(Paint.Style.STROKE);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.DKGRAY);
        float[] fillPs = {100, 100, 300, 300};
        float[] fillAndStrokePs = {400, 100, 600, 300};
        float[] strokePs = {700, 100, 900, 300};

        canvas.drawRect(fillPs[0], fillPs[1], fillPs[2], fillPs[3], fillPaint);
        canvas.drawRect(fillAndStrokePs[0], fillAndStrokePs[1], fillAndStrokePs[2], fillAndStrokePs[3], fillAndStrokePaint);
        canvas.drawRect(strokePs[0], strokePs[1], strokePs[2], strokePs[3], strokePaint);
    }
}

スタイル

列挙値 内容
Paint.Style.FILL 図形を塗りつぶす(枠線描画なし)
Paint.Style.ROUND 図形を塗りつぶし、枠線も描画
Paint.Style.SQUARE 図形の枠線のみを描画

xml側

上記の書き方を参照

円 / 楕円

TODO: 円 / 楕円について記述する

テキスト

TODO: テキストについて記述する

画像

TODO: 画像について記述する

パス

TODO: パスについて記述する

Discussion

ログインするとコメントできます