第2話 SurfaceView 入門

 パッケージ名を「home.part02」としてプロジェクトを作成したとすると、自動で以下のようなソースが生成されるかと思います。

part02.java
package home.part02; import android.app.Activity; import android.os.Bundle; public class part02 extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } }

 SurfaceView を使用するためには、メソッド setContentView の引数に、「R.layout.main」ではなく、android.view.SurfaceView クラスのインスタンスを指定します。このコンストラクタの引数には自分自身のインスタンスを指定します。

setContentView( new android.view.SurfaceView( this ) );

 これを実行しても何も表示されませんが、一応、SurfaceView のプログラムということになります。


 上記の変更により、SurfaceView を使用することが出来ました。しかし実際には、SurfaceView クラスを直接インスタンス化したりすることはせず、継承するのが一般的です。何故かというと、その方が都合が良いからです。どう都合よいかというのは、今後の話から見えてくるかと思いますので、ここでは少々腑に落ちないかもしれませんが、騙されたと思って継承クラスを作成してみて下さい。

part02.java
package home.part02; import android.app.Activity; import android.os.Bundle; public class part02 extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView( new MyView( this ) ); } } class MyView extends android.view.SurfaceView { public MyView( android.content.Context context ) { super( context ); } }

 これを実行しても、やはり何も表示されないと思いますが、これで任意の描画を行なう準備が出来ました。


 では早速、描画内容を変更してみたいと思います。本来であればここで文字列「Hello World」を表示すべきなのかもしれませんが、ここではより簡単な「背景色の変更」を行なってみたいと思います。

 背景色の変更は、基本的には起動時に1回行なうだけだと思いますので、継承クラスのコンストラクタ内で行なえば良いような気がします。しかし実際にはコンストラクタ時ではタイミングが早すぎて設定することが出来ません。ではどうするのかというと、「SurfaceView が作成完了したとき」というイベントを取得することができますので、そこで設定することになります。

 SurfaceView 作成完了の知らせを受け取るには、android.view.SurfaceHolder.Callback というインターフェースを実装する必要があります。私の動画のみで Java を学習された方は「インターフェース」をご存知無いかと思いますが、これは「必ずオーバーライドする必要があるメソッドのみで構成されたクラス」といった感じのものです。これをクラスの継承のように扱うのですが、その際のキーワードが「extends」ではなく「implements」になります。

 とりあえず、Callback インターフェースの実装のみ行なってみます。Callback インターフェースには3つのメソッドが定義されていますので、3つオーバーライドを行なう必要があります。

part02.java
package home.part02; import android.app.Activity; import android.os.Bundle; public class part02 extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView( new MyView( this ) ); } } class MyView extends android.view.SurfaceView implements android.view.SurfaceHolder.Callback { public MyView( android.content.Context context ) { super( context ); } /** * これが呼び出されるのは、Surface のいくつかの構造(フォーマットやサイズ)が変化した直後です。 */ @Override public void surfaceChanged( android.view.SurfaceHolder holder, int format, int width, int height ) { } /** * これが呼び出されるのは、Surface が初回作成された直後です。 */ @Override public void surfaceCreated( android.view.SurfaceHolder holder ) { } /** * これが呼び出されるのは、Surface が破棄される直前です。 */ @Override public void surfaceDestroyed( android.view.SurfaceHolder holder ) { } }

 これで作成完了通知を受け取る準備が整いました。実際に受け取るには android.view.SurfaceHolder.addCallback メソッドにて通知対象の SurfaceView を指定する必要があります。このメソッドの引数に、通知を送る側の SurfaceView のインスタンスを指定します。今回のソースでは、通知を送る側も受け取る側も同じクラスですので、this を指定することになります。これをコンストラクタで行なっておきます。

public MyView( android.content.Context context ) { super( context ); getHolder().addCallback( this ); }

 これでやっと、3つそれぞれのオーバーライドしたメソッドが呼び出されるようになります。今回の目的は、作成時での背景色変更ですから、実際に利用するのは surfaceCreated メソッドだけになります。他2つは利用しないのですが、インターフェースなので仕方なく記述しているだけですね。

/** * これが呼び出されるのは、Surface が初回作成された直後です。 */ @Override public void surfaceCreated( android.view.SurfaceHolder holder ) { android.graphics.Canvas ca = holder.lockCanvas(); // Surface の編集を開始する ca.drawColor( android.graphics.Color.BLUE ); // キャンバスの背景色を「青」に設定する holder.unlockCanvasAndPost( ca ); // Surface の編集を終了する }

 これを実行すると背景色が青で表示され、やっと描画内容に変化を付けられるようになりました。

part02実行結果

 正直、ここまで辿り着くのに長すぎると思われる方も多いと思います。ただ、実際のところ、今回の内容は一度記述してしまえば2度と変更することが無いようなテンプレート的なものですので、あまり正確に理解できなかったとしても大きな問題はありません。ですのでここで心が折れたりしないで下さいね。次回から、一般的な「Hello World」になりますので、ここまでの中身はぶっちゃけ無視してもらっても構わないと思います。


part02.java
package home.part02; import android.app.Activity; import android.os.Bundle; public class part02 extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView( new MyView( this ) ); } } class MyView extends android.view.SurfaceView implements android.view.SurfaceHolder.Callback { public MyView( android.content.Context context ) { super( context ); getHolder().addCallback( this ); } /** * これが呼び出されるのは、Surface のいくつかの構造(フォーマットやサイズ)が変化した直後です。 */ @Override public void surfaceChanged( android.view.SurfaceHolder holder, int format, int width, int height ) { } /** * これが呼び出されるのは、Surface が初回作成された直後です。 */ @Override public void surfaceCreated( android.view.SurfaceHolder holder ) { android.graphics.Canvas ca = holder.lockCanvas(); // Surface の編集を開始する ca.drawColor( android.graphics.Color.BLUE ); // キャンバスの背景色を「青」に設定する holder.unlockCanvasAndPost( ca ); // Surface の編集を終了する。 } /** * これが呼び出されるのは、Surface が破棄される直前です。 */ @Override public void surfaceDestroyed( android.view.SurfaceHolder holder ) { } }

【次】第3話 SurfaceView の Hello World


[戻る]
管理人:T.Umezawa
最終更新日時:2014/11/05