画面に図形を描画する - Android

画面に図形を描画するコードを紹介します。

プロジェクトの作成

Android アプリケーションプロジェクトを作成します。
[New Android Application]ダイアログボックスが表示されますので、以下を設定します。
  • Application Name: "CanvasDraw"
  • Project Name: "CanvasDraw"
  • Package Name: "com.iPentec.canvasdraw"
  • Minimum Required SDK: "API 8: Android 2.2 (Froyo)"
  • Target SDK: "API 17: Android 4.2 (Jelly Bean)"
  • Compile With: "API 17: Android 4.2 (Jelly Bean)"
  • Theme: "Holo Light with Dark Action Bar"

ビューの追加

画面に図形を描画する場合はカスタム化したViewクラスを用います。ビューの追加手順を紹介します。

"Package Explorer"のプロジェクトのノードを選択し右クリックします。[New]メニューの[Other]メニューを選択します。


[New]ダイアログが表示されます。一覧から[Android]カテゴリの[Android Object]を選択します。選択後[Next]ボタンを押します。


[New Android Object]ダイアログが表示されます。一覧から"Custom View"を選択し、[Next]ボタンを押します。


カスタムビューのクラス名を設定します。今回は"MyView"としました。設定ができたら[Next]ボタンを押します。


プレビュー画面が表示され、コードの変更部分などが確認できます。[Finish]ボタンを押してカスタムビューの追加を完了します。

コード

UIをデザインする前にカスタムビューを含むコードを記述します。

MainActivity.java

package com.iPentec.canvasdraw;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;

public class MainActivity extends Activity {

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

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
  }
}

MyView.java

package com.iPentec.canvasdraw;

import java.util.Random;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.view.View;

/**
 * TODO: document your custom view class.
 */
public class MyView extends View {
  private String mExampleString; // TODO: use a default from R.string...
  private int mExampleColor = Color.RED; // TODO: use a default from R.color...
  private float mExampleDimension = 0; // TODO: use a default from R.dimen...
  private Drawable mExampleDrawable;

  private TextPaint mTextPaint;
  private float mTextWidth;
  private float mTextHeight;

  public MyView(Context context) {
    super(context);
    init(null, 0);
  }

  public MyView(Context context, AttributeSet attrs) {
    super(context, attrs);
    init(attrs, 0);
  }

  public MyView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    init(attrs, defStyle);
  }

  private void init(AttributeSet attrs, int defStyle) {
    // Load attributes
  }

  private void invalidateTextPaintAndMeasurements() {
    mTextPaint.setTextSize(mExampleDimension);
    mTextPaint.setColor(mExampleColor);
    mTextWidth = mTextPaint.measureText(mExampleString);

    Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
    mTextHeight = fontMetrics.bottom;
  }

  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
   
    // TODO: consider storing these as member variables to reduce
    // allocations per draw cycle.
    int paddingLeft = getPaddingLeft();
    int paddingTop = getPaddingTop();
    int paddingRight = getPaddingRight();
    int paddingBottom = getPaddingBottom();

    int contentWidth = getWidth() - paddingLeft - paddingRight;
    int contentHeight = getHeight() - paddingTop - paddingBottom;
    
    Rect r = new Rect(0,0,canvas.getWidth(), canvas.getHeight());
    Paint p = new Paint();
    p.setColor(Color.argb(255, 0, 0, 0));
    canvas.drawRect(r, p);
  }

  /**
   * Gets the example string attribute value.
   * 
   * @return The example string attribute value.
   */
  public String getExampleString() {
    return mExampleString;
  }

  /**
   * Sets the view's example string attribute value. In the example view, this
   * string is the text to draw.
   * 
   * @param exampleString
   *          The example string attribute value to use.
   */
  public void setExampleString(String exampleString) {
    mExampleString = exampleString;
    invalidateTextPaintAndMeasurements();
  }

  /**
   * Gets the example color attribute value.
   * 
   * @return The example color attribute value.
   */
  public int getExampleColor() {
    return mExampleColor;
  }

  /**
   * Sets the view's example color attribute value. In the example view, this
   * color is the font color.
   * 
   * @param exampleColor
   *          The example color attribute value to use.
   */
  public void setExampleColor(int exampleColor) {
    mExampleColor = exampleColor;
    invalidateTextPaintAndMeasurements();
  }

  /**
   * Gets the example dimension attribute value.
   * 
   * @return The example dimension attribute value.
   */
  public float getExampleDimension() {
    return mExampleDimension;
  }

  /**
   * Sets the view's example dimension attribute value. In the example view,
   * this dimension is the font size.
   * 
   * @param exampleDimension
   *          The example dimension attribute value to use.
   */
  public void setExampleDimension(float exampleDimension) {
    mExampleDimension = exampleDimension;
    invalidateTextPaintAndMeasurements();
  }

  /**
   * Gets the example drawable attribute value.
   * 
   * @return The example drawable attribute value.
   */
  public Drawable getExampleDrawable() {
    return mExampleDrawable;
  }

  /**
   * Sets the view's example drawable attribute value. In the example view, this
   * drawable is drawn above the text.
   * 
   * @param exampleDrawable
   *          The example drawable attribute value to use.
   */
  public void setExampleDrawable(Drawable exampleDrawable) {
    mExampleDrawable = exampleDrawable;
  }
}

解説

MainActivity.javaは修正はしません。
MyView.javaはonDraw()メソッド内にコードを記述します。
OnDraw() メソッド
下記のOnDrawメソッドが画面の更新時に実行されるメソッドです。このメソッド内に画面描画処理を記述します。
  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
   
    // TODO: consider storing these as member variables to reduce
    // allocations per draw cycle.
    int paddingLeft = getPaddingLeft();
    int paddingTop = getPaddingTop();
    int paddingRight = getPaddingRight();
    int paddingBottom = getPaddingBottom();

    int contentWidth = getWidth() - paddingLeft - paddingRight;
    int contentHeight = getHeight() - paddingTop - paddingBottom;
    
    Rect r = new Rect(0,0,canvas.getWidth(), canvas.getHeight());
    Paint p = new Paint();
    p.setColor(Color.argb(255, 0, 0, 0));
    canvas.drawRect(r, p);
  }

    int paddingLeft = getPaddingLeft();
    int paddingTop = getPaddingTop();
    int paddingRight = getPaddingRight();
    int paddingBottom = getPaddingBottom();

    int contentWidth = getWidth() - paddingLeft - paddingRight;
    int contentHeight = getHeight() - paddingTop - paddingBottom;
上記の6行は画面の描画領域の寸法を取得するコードです。今回は利用しません。

  Rect r = new Rect(0,0,canvas.getWidth(), canvas.getHeight());
画面を塗りつぶすための矩形を作成します。canvas.getWidth(), canvas.getHeight()メソッドを呼び出すことでキャンバスの幅と高さを取得できます。上記のコードでは画面全体囲む矩形を作成しています。

  Paint p = new Paint();
画面を塗りつぶすためのペンを準備します。

  p.setColor(Color.argb(255, 0, 0, 0));
先の行で準備したペンに色を設定指定します。Color.argbに与えている引数は、第一引数から、透明度、R成分、G成分、B成分となっています。今回、不透明の黒で塗りつぶすので透明度は255にします。他の引数は0にします。

  canvas.drawRect(r, p);
画面に矩形を描画します。第一引数に塗りつぶす矩形のRectオブジェクトを、第二引数に描画に使うペンオブジェクトを与えます。

UI

UIを作成します。MainActivityのレイアウトファイルを開きます。下図のデザイナ画面が表示されます。


デザイナ画面の左側の[Palette]の"Custom & Library Views"カテゴリを選択します。一覧に[MyView]コントロールが追加されていますので、これをフォームにドラッグ&ドロップします。


ドロップできるとフォームにMyViewが配置できます。

実行結果

上記のプロジェクトを実行すると下図の画面が表示されます。MyViewのコントロール内部が黒で塗りつぶされました。

パラメータの変更

onDrawメソッドを下記に変更します。
  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    
    Rect r = new Rect(0,0,canvas.getWidth(), canvas.getHeight());
    Paint p = new Paint();
    p.setColor(Color.argb(255, 0, 128, 0));
    canvas.drawRect(r, p);
  }

実行すると下図の結果となります。G成分を128にしたので緑色で塗りつぶされました。

描画する図形を増やす

onDrawメソッドを下記に変更します。
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    
    // TODO: consider storing these as member variables to reduce
    // allocations per draw cycle.
    int paddingLeft = getPaddingLeft();
    int paddingTop = getPaddingTop();
    int paddingRight = getPaddingRight();
    int paddingBottom = getPaddingBottom();

    int contentWidth = getWidth() - paddingLeft - paddingRight;
    int contentHeight = getHeight() - paddingTop - paddingBottom;
    
    Rect r = new Rect(0,0,canvas.getWidth(), canvas.getHeight());
    Paint p = new Paint();
    p.setColor(Color.argb(255, 0, 0, 0));
    canvas.drawRect(r, p);

    Rect rs = new Rect(200,200,200+32,200+32);
    Paint ps = new Paint();
    ps.setColor(Color.argb(255, 160, 160, 255));
    canvas.drawRect(rs, ps);
  }

  Rect rs = new Rect(200,200,200+32,200+32);
  Paint ps = new Paint();
  ps.setColor(Color.argb(255, 160, 160, 255));
  canvas.drawRect(rs, ps);
を追加しました。(x,y)=(200,200)の位置に幅32、高さ32の矩形を描画します。カラーは(R,G,B)=(160,160,255)です。

プロジェクトを実行すると下図の結果となります。

描画する図形を増やす2

図形が一つだけでは寂しいので、乱数を用いて矩形を64個描画させるコードが下記です。
  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    
    
    // TODO: consider storing these as member variables to reduce
    // allocations per draw cycle.
    int paddingLeft = getPaddingLeft();
    int paddingTop = getPaddingTop();
    int paddingRight = getPaddingRight();
    int paddingBottom = getPaddingBottom();

    int contentWidth = getWidth() - paddingLeft - paddingRight;
    int contentHeight = getHeight() - paddingTop - paddingBottom;
    
    Rect r = new Rect(0,0,canvas.getWidth(), canvas.getHeight());
    Paint p = new Paint();
    p.setColor(Color.argb(255, 0, 0, 0));
    canvas.drawRect(r, p);

    //
    Random rnd = new Random();
    for (int i=0;i<64; i++){
      int rx = rnd.nextInt(canvas.getWidth());
      int ry = rnd.nextInt(canvas.getHeight());
  
      int rr = rnd.nextInt(255);
      int rg = rnd.nextInt(255);
      int rb = rnd.nextInt(255);
       
      Rect rs = new Rect(rx,ry,rx+32,ry+32);
      Paint ps = new Paint();
      ps.setColor(Color.argb(255, rr, rg, rb));
      canvas.drawRect(rs, ps);
    }
  }

実行すると下図の結果となります。

著者
iPentecのプログラマー、最近はAIの積極的な活用にも取り組み中。
とっても恥ずかしがり。
最終更新日: 2024-01-04
作成日: 2013-03-08
iPentec all rights reserverd.