SurfaceViewを使ってみました
皆さんにとってAndroidの画面に関する部分というと、ButtonやTextViewといった所謂Viewが馴染みが深いところでしょうか。
ViewはsetContentView()メソッドを用いることにより、画面に追加することができます。
ところで、アニメーション等を使用したい場合、かなり細かいところまで制御する必要が出てきます。
またその場合、描画面を自分で操作することもあります。
そのようなときにSurfaceViewを使用します。
SurfaceViewでは以下の一連の流れで描画を行います。(基本的には)
- ロックとCanvasの取得
- 描画
- アンロックと更新
lockCanvas:画面のサーフェイスをロックし、描画の為のCanvasを返す
描画処理
unlockCanvasAndPost:画面のロックを解除し、表示を更新
サンプルプログラム
package com.example.surfaceviewsample;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class MainActivity extends Activity {
private static final String TAG = "SurfaceViewSample";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MainView view = new MainView(this);
setContentView(view);
}
// SurfaceViewクラスを継承したクラスを作成
class MainView extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder holder = null;
private int[] color = { Color.YELLOW, Color.BLUE, Color.RED,
Color.GREEN };
private int idx = 0;
// MainViewクラスのコンストラクタ
public MainView(Context context) {
super(context);
// getHolder()メソッドを用いてSurfaceHolderオブジェクトを取得
holder = getHolder();
// addCallback()を用いて、SurfaceHolder.Callbackオブジェクトをリスナー登録する
holder.addCallback(this);
}
// SurfaceViewのサイズなどが変更されたときに呼び出されるメソッド
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
Log.e(TAG, "surfaceChanged()");
}
// SurfaceViewが最初に生成されたときに呼び出されるメソッド
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.e(TAG, "surfaceCreated()");
draw();
}
// SurfaceViewが破棄されるときに呼び出されるメソッド
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.e(TAG, "surfaceDestroyed()");
}
// SurfaceViewにてタッチイベントが検知されたときに呼び出される
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.e(TAG, event.toString());
// getAction()メソッドを用いて、eventよりタッチイベントのアクションを取得
if (event.getAction() == MotionEvent.ACTION_UP) {
draw();
}
return true;
}
// 描画
private void draw() {
// lockCanvas()メソッドを使用して、描画するためのCanvasオブジェクトを取得する
Canvas canvas = holder.lockCanvas();
// 画面全体を一色で塗りつぶすdrawColor()メソッドを用いて画面全体を白に指定
canvas.drawColor(Color.WHITE);
// Paintクラスをインスタンス化
Paint paint = new Paint();
// カラーを指定
paint.setColor(color[idx]);
// Canvas.drawRect()を呼び出すと、正方形や長方形を描画することが可能になる
// (left:左辺,top:上辺,right:右辺,bottom:下辺,Paintインスタンス)
canvas.drawRect(50, 100, 200, 300, paint);
// Canvasオブジェクトへの描画完了したら、unlockCanvasAndPost()メソッドを呼び出し、引数にはCanvasオブジェクトを指定する
holder.unlockCanvasAndPost(canvas);
// 三項演算子( 条件式 ? 式1 : 式2)
// ?の前までがif文の条件式
// ?の前の値がtrue→:の前の値が返される
// ?の前の値がfalse:の後の値が返される
idx = (idx == color.length - 1) ? 0 : idx + 1;
}
}
}
追記事項
記事内で使っているメソッドと引数は以下の通りです。
- surfaceChanged()
- surfaceCreated()
- surfaceDestroyed()
- onTouchEvent()
45行目のsurfaceChanged()メソッドは、SurfaceViewの変更時に呼び出されるメソッドです。
引数は下表の通りです。
| データ型 | 引数名 | 概要 |
|---|---|---|
| SurfaceHolder | holder | 変更されたSurfaceViewのSurfaceHolderホルダー |
| int | format | 変更されたSurfaceViewのピクセル形式 |
| int | width | 変更されたSurfaceViewの横幅 |
| int | height | 変更されたSurfaceViewの縦幅 |
52行目のsurfaceChanged()メソッドは、SurfaceViewが最初に生成されたときに呼び出されるメソッドです。
引数は下表の通りです。
| データ型 | 引数名 | 概要 |
|---|---|---|
| SurfaceHolder | holder | SurfaceViewが生成されるSurfaceHolderオブジェクト |
59行目のsurfaceChanged()メソッドは、SurfaceViewが破棄されるときに呼び出されるメソッドです。
引数は下表の通りです。
| データ型 | 引数名 | 概要 |
|---|---|---|
| SurfaceHolder | holder | SurfaceViewが破棄されるSurfaceHolderオブジェクト |
65行目のsurfaceChanged()メソッドは、SurfaceViewにてタッチイベントが検知されたときに呼び出される
| データ型 | 引数名 | 概要 |
|---|---|---|
| MotionEvent | event | 発生したタッチイベント等が格納されているeventオブジェクト |
68行目の条件式の値には、以下の値を指定することができます。
| 定数名 | 概要 |
|---|---|
| ACTION_DOWN | タッチ(押下)した場合 |
| ACTION_MOVE | タッチしたまま離さずにスライドした場合 |
| ACTION_UP | タッチした状態から指を持ち上げた場合 |
| ACTION_CANCEL | UPとDOWNの同時発生の場合 |
| ACTION_OUTSIDE | ターゲットとなっているUIの範囲外をタッチした場合 |