Draw

MVC モデル

図形の描画を担当しているのが、真ん中の CustomViewになります。

ただ、その説明を行う前に、まずは MVC モデルの簡単な説明を、pdf 資料をつかっておこないます。

Model の作成

まずは Model ですね。四角形のリストを保持したいのですが、、android.graphics.RectF があるので、それを使いましょう。List<RectF> shapesを準備しました。

点を追加するメソッドaddShape(PointF, PointF), 最期の図形を取り除くundo(), 全図形を取り除くreset() も作ってしまいましょう。

これで、モデルはほぼ完了ですね。

っていいたいところですが、入力中の図形を赤色表示するためにModelを少し強化しておきます。 図形の入力は、マウスをpressして(始点)、ドラッグ中の座標は終点候補で、リリースしたタイミングで終点確定となります。 始点をPointF dragBegin, 終点候補をPointF dragCurrentと、フィールドとして設けましょう。 図形入力中は dragBegin, dragCurrentnullでない値をとることとします。

描画ルーチンの作成

Model を表示するためのメソッドを作成しましょう。onDraw(Canvas) です。 ここでも、inteface の規約にのっとってシステムがユーザ定義関数を呼び出すってことがおこなわれています。

android.graphics.Canvas には、描画用のメソッドがあるので、そちらをつかって図形を書きます。 描画中のものがある場合は、赤い四角で描画します。

@Override
protected void onDraw(Canvas canvas) {
    Paint bluePaint = new Paint();
    bluePaint.setColor(Color.BLUE);
    Paint redPaint = new Paint();
    redPaint.setColor(Color.RED);
    for(RectF shape: shapes) {
        canvas.drawRect(shape, bluePaint);
    }
    if(dragCurrent!=null) {
        canvas.drawRect(genRect(dragBegin, dragCurrent), redPaint);
    }
}

やっている中身は、

  • 各四角形を順番に青で塗って、
  • 描画中の四角があれば、赤で塗る

ってだけです。

Event 処理の中身

Controller を実現するには、ユーザのGUI操作に応じた処理を定義してやらなくてはいけません。 で、各種 Event に応じた処理を Event Handler として記述することで実現します。

今回だと、ユーザ操作は、「マウスをpressして(始点)、ドラッグ中の座標は終点候補で、リリースしたタイミングで終点確定」って感じですが、 android.view.ViewonTouchEvent(MotionEvent e)を再定義することで定義できます。(参考: android.view.MotionEvent)

e.getAction()MotionEvent の種類をとれるので、

  • MotionEvent.ACTION_DOWN の時は、始点を取得する処理を登録。
  • MotionEvent.ACTION_MOVE の時は、ドラッグ中の終点候補を更新
  • MotionEvent.ACTION_UP の時は、終点確定時の処理を実現

てな感じです。それぞれ、適切に Model の更新を行いえばOKです。 こんな感じ。

@Override
public boolean onTouchEvent(MotionEvent e) {
    PointF point = new  PointF(e.getX(), e.getY());
    switch(e.getAction()){
        case MotionEvent.ACTION_DOWN:
            dragBegin = point;
            invalidate();
            break;
        case MotionEvent.ACTION_UP:
            shapes.add(genRect(dragBegin, point));
            dragBegin = dragCurrent = null;
            invalidate();
            performClick();
            break;
        case MotionEvent.ACTION_MOVE:
            dragCurrent = point;
            invalidate();
            break;
    }
    return true;
}
public boolean performClick() {
    super.performClick();
    return true;
}

ポイントは

  • Modelを変更したら、再描画のための **invalidate()** を呼ぶのをわすれないように。
  • toTOuchEvent を override すると、performClick() の意味も変わるので、override しています。

練習問題

  • 描画する色を変えてみましょう
  • 描画する図形もかけてみましょう。android.graphics.Canvas のメソッドを探してみましょう
  • 図形を追加した際、図形の始点・終点情報を、message area に表示してみましょう。message(String msg) メソッドを用意してあるので、使ってみてください。

Read more