📚
ビュー描画の基礎(View / Canvas / Paint)
はじめに
View・Canvas・Paintの簡単な使用例を備忘録として記述しています。
開発環境
Android | 10 |
---|---|
AndroidStudio | Bumblebee |
macOS | 12.3 |
minSdk | 28 |
targetSdk | 31 |
実行端末 | Pixel3a |
参考資料
View
Canvas 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
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
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
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側
円 / 楕円
drawCircle
drawOval
Java側
CircleView.java
public class CircleView extends View {
private Paint circlePaint;
private Paint ellipsePaint;
private final RectF rectf = new RectF(400, 100, 900, 400);
public CircleView(Context context) {
super(context);
}
public CircleView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
circlePaint = new Paint();
circlePaint.setColor(Color.CYAN);
circlePaint.setStrokeWidth(20);
circlePaint.setStyle(Paint.Style.FILL_AND_STROKE);
ellipsePaint = new Paint();
ellipsePaint.setColor(Color.BLUE);
ellipsePaint.setStrokeWidth(20);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.DKGRAY);
canvas.drawCircle(200, 200, 100, circlePaint);
canvas.drawOval(rectf, ellipsePaint);
}
}
xml側
直線
直線の描画を行います。
先端の形状を指定することが可能です。
drawLine
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側
テキスト
drawText
Java側
TextView.java
public class TextView extends View {
private final String TAG = getClass().getSimpleName();
private Paint paint;
public TextView(Context context) {
super(context);
}
public TextView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
paint = new Paint();
paint.setColor(Color.WHITE);
paint.setStrokeWidth(5);
// フォントの種類
paint.setTypeface(Typeface.SANS_SERIF);
// テキストサイズ(sp)
paint.setTextSize(40.0f);
// 表示位置
paint.setTextAlign(Paint.Align.CENTER);
// 水平方向への拡大率
paint.setTextScaleX(1.0f);
// 水平方向にずらす度合い
paint.setTextSkewX(0.0f);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Log.d(TAG, "onDraw: ");
canvas.drawColor(Color.DKGRAY);
canvas.drawText("TextViewテスト", 300, 300, paint);
}
}
xml側
画像
drawBitmap
Java側
ImageView.java
public class ImageView extends View {
private Paint paint;
private Bitmap baseBmp;
private Rect rect = new Rect(150, 100, 450, 400);
private RectF rectF = new RectF(0, 400, 800, 800);
public ImageView(Context context) {
super(context);
}
public ImageView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
baseBmp = BitmapFactory.decodeResource(getResources(), R.drawable.luffy);
paint = new Paint();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.DKGRAY);
canvas.drawBitmap(baseBmp, 0, 10, paint);
canvas.drawBitmap(baseBmp, rect, rectF, paint);
}
}
xml側
パス
drawPath
Java側
PathView.java
public class PathView extends View {
private Paint paint;
private Path path;
public PathView(Context context) {
super(context);
}
public PathView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
paint = new Paint();
path = new Path();
paint.setColor(Color.CYAN);
paint.setStrokeWidth(20);
paint.setStyle(Paint.Style.STROKE);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.DKGRAY);
// 平たい角
path.reset();
path.moveTo(210, 400);
path.lineTo(240, 750);
path.lineTo(270, 400);
paint.setStrokeJoin(Paint.Join.BEVEL);
canvas.drawPath(path, paint);
// 鋭角
path.reset();
path.moveTo(400, 400);
path.lineTo(440, 750);
path.lineTo(470, 400);
paint.setStrokeMiter(30);
paint.setStrokeJoin(Paint.Join.MITER);
canvas.drawPath(path, paint);
// 丸角
path.reset();
path.moveTo(600, 400);
path.lineTo(640, 750);
path.lineTo(670, 400);
paint.setStrokeJoin(Paint.Join.ROUND);
canvas.drawPath(path, paint);
}
}
Discussion