SurfaceViewのコード記述方法について - SurfaceViewのコールバックを別クラスにする - Android
SurfaceViewのコードの記述方法についての紹介です。
SurfaceViewの基本コード
SurfaceViewの基本コードは以下になります。
MySurfaceView.java
package com.iPentec.simplesurfaceview;
import android.content.Context;
import android.util.AttributeSet;
import android.view.*;
import android.view.SurfaceHolder.Callback;
/**
* TODO: document your custom view class.
*/
public class MySurfaceView extends SurfaceView implements Callback{
public MySurfaceView(Context context) {
super(context);
}
public MySurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MySurfaceView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public void surfaceCreated(SurfaceHolder arg0){
}
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3){
}
@Override
public void surfaceDestroyed(SurfaceHolder arg0){
}
}
コード記述方法 その1 (SurfaceViewのコールバックをSurfaceViewのクラスとする)
画面描画やViewの作成や廃棄のコールバックをSurfaceViewのクラス自身で受け取る方式のコード記述です。
UI
MainActivityにMySurfaceViewを配置します。
コード
以下のコードを記述します。
MySurfaceView.java
package com.iPentec.simplesurfaceview;
import android.content.Context;
import android.util.AttributeSet;
import android.view.*;
import android.view.SurfaceHolder.Callback;
import android.graphics.*;
/**
* TODO: document your custom view class.
*/
public class MySurfaceView extends SurfaceView implements Callback {
private SurfaceHolder holder = null;
public MySurfaceView(Context context) {
super(context);
initSurface();
}
public MySurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
initSurface();
}
public MySurfaceView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initSurface();
}
@Override
public void surfaceCreated(SurfaceHolder arg0) {
drawSurface();
}
@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
}
@Override
public void surfaceDestroyed(SurfaceHolder arg0) {
}
public void initSurface() {
holder = this.getHolder();
holder.addCallback(this);
}
public void drawSurface() {
Canvas canvas = holder.lockCanvas();
canvas.drawColor(Color.WHITE);
Paint paint = new Paint();
paint.setColor(Color.GREEN);
canvas.drawRect(100, 100, 150, 150, paint);
holder.unlockCanvasAndPost(canvas);
}
}
解説
このコードではMySurfaceViewのクラス自身がSurfaceViewのコールバックを受け取るため、MySurfaceViewクラスにコールバックを受け取るためのCallback (正確には SurfaceHolder.Callback)インターフェイスをimplementsで実装します。
SurfaceHolder.Callbackインターフェイスを実装したクラスはsurfaceCreated, surfaceChanged, surfaceDestroyedメソッドをオーバーライドする必要があります。オーバーライドされたメソッドがSurfaceViewからのコールバックとして呼び出されます。SurfaceViewの初期化時にはSurfaceHolderオブジェクトのaddCallback()メソッドを呼び出しコールバック先のコールバッククラスを指定する必要があります。上記のコードではMySurfaceViewクラス自身がコールバックを受けるため、initSurfaceメソッド内で
holder.addCallback(this);
と"this"を引数に与え自分自身をコールバック先として指定しています。
MainActivity.java
package com.iPentec.simplesurfaceview;
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;
}
}
実行結果
プロジェクトを実行します。下図の画面が実行結果として表示されます。
コード記述方法 その2 (SurfaceViewのコールバックを匿名クラスとする)
画面描画やViewの作成や廃棄のコールバックをSurfaceViewのクラス内部で定義、作成した匿名クラスで受け取る方式のコード記述です。
UI
MainActivityにMySurfaceViewを配置します。
コード
以下のコードを記述します。MySurfaceView.javaはパターンA、パターンBのどちらでも同じ動作になります。
MySurfaceView.java (パターンA)
package com.iPentec.simplesurfaceview2;
import android.content.Context;
import android.view.SurfaceView;
import android.view.SurfaceHolder;
import android.graphics.Paint;
import android.graphics.Color;
import android.graphics.Canvas;
import android.util.AttributeSet;
public class MySurfaceView extends SurfaceView{
Paint p;
public MySurfaceView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
init();
}
public MySurfaceView(Context context, AttributeSet attrs)
{
super(context, attrs);
init();
}
public MySurfaceView(Context context)
{
super(context);
init();
}
private void init(){
p = new Paint();
p.setColor(Color.RED);
SurfaceHolder surfaceHolder = getHolder();
surfaceHolder.addCallback(
new SurfaceHolder.Callback() {
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
draw(holder);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
}
);
}
private void draw(SurfaceHolder holder){
Canvas canvas = holder.lockCanvas();
canvas.drawColor(Color.GRAY);
canvas.drawCircle(100, 100, 25, p);
holder.unlockCanvasAndPost(canvas);
}
}
MySurfaceView.java (パターンB)
package com.iPentec.simplesurfaceview2;
import android.content.Context;
import android.view.SurfaceView;
import android.view.SurfaceHolder;
import android.graphics.Paint;
import android.graphics.Color;
import android.graphics.Canvas;
import android.util.AttributeSet;
public class MySurfaceView extends SurfaceView{
Paint p;
public MySurfaceView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
init();
}
public MySurfaceView(Context context, AttributeSet attrs)
{
super(context, attrs);
init();
}
public MySurfaceView(Context context)
{
super(context);
init();
}
private void init(){
p = new Paint();
p.setColor(Color.RED);
SurfaceHolder surfaceHolder = getHolder();
SurfaceHolder.Callback callback = new SurfaceHolder.Callback() {
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
draw(holder);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
};
surfaceHolder.addCallback(callback);
}
private void draw(SurfaceHolder holder){
Canvas canvas = holder.lockCanvas();
canvas.drawColor(Color.GRAY);
canvas.drawCircle(100, 100, 25, p);
holder.unlockCanvasAndPost(canvas);
}
}
解説
このコードではMySurfaceView内に記述した匿名クラスがSurfaceViewのコールバックを受け取ります。コード中の"new SurfaceHolder.Callback()"の後の"{"~"}"部分に匿名クラスの実装を記述します。
パターンAではSurfaceHolder.addCallbackの引数内に匿名クラスのインスタンスを直接与えています。バターンBではSurfaceHolder.Callbackの変数にインスタンスを作成し、その変数をSurfaceHolder.addCallback()の引数に与えています。
コールバックは匿名クラスのsurfaceDestroyed, surfaceCreated, surfaceChangedメソッドが呼び出されます。
MainActivity.java
package com.iPentec.simplesurfaceview2;
import android.content.Context;
import android.view.SurfaceView;
import android.view.SurfaceHolder;
import android.graphics.Paint;
import android.graphics.Color;
import android.graphics.Canvas;
import android.util.AttributeSet;
public class MySurfaceView extends SurfaceView{
Paint p;
public MySurfaceView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
init();
}
public MySurfaceView(Context context, AttributeSet attrs)
{
super(context, attrs);
init();
}
public MySurfaceView(Context context)
{
super(context);
init();
}
private void init(){
p = new Paint();
p.setColor(Color.RED);
SurfaceHolder surfaceHolder = getHolder();
MySurfaceViewCallback msvc = new MySurfaceViewCallback();
surfaceHolder.addCallback(msvc);
}
}
実行結果
プロジェクトを実行します。下図の画面が実行結果として表示されます。
コード記述方法 その3 (SurfaceViewのコールバックを別のクラスで受ける)
画面描画やViewの作成や廃棄のコールバックを別のクラスで受け取る方式のコード記述です。
UI
MainActivityにMySurfaceViewを配置します。
コード
以下のコードを記述します。
MySurfaceView.java
package com.iPentec.simplesurfaceview2;
import android.content.Context;
import android.view.SurfaceView;
import android.view.SurfaceHolder;
import android.graphics.Paint;
import android.graphics.Color;
import android.graphics.Canvas;
import android.util.AttributeSet;
public class MySurfaceView extends SurfaceView{
Paint p;
public MySurfaceView(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
init();
}
public MySurfaceView(Context context, AttributeSet attrs)
{
super(context, attrs);
init();
}
public MySurfaceView(Context context)
{
super(context);
init();
}
private void init(){
p = new Paint();
p.setColor(Color.RED);
SurfaceHolder surfaceHolder = getHolder();
MySurfaceViewCallback msvc = new MySurfaceViewCallback();
surfaceHolder.addCallback(msvc);
}
}
解説
このコードではSurfaceViewのコールバックは下記のMySurfaceViewCallbackクラスのメソッドで受けます。MySurfaceViewlクラスでは、MySurfaceViewCallbackクラスのインスタンスを作成し、SurfaceViewのSurfaceHolderのaddCallbackメソッドを呼び出して、MySurfaceViewCallbackのインスタンスを与えてMySurfaceViewCallbackクラスをコールバック先に指定します。
MySurfaceViewCallback.java
package com.iPentec.simplesurfaceview2;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.SurfaceHolder;
public class MySurfaceViewCallback implements SurfaceHolder.Callback {
Paint p;
public MySurfaceViewCallback(){
p = new Paint();
p.setColor(Color.BLUE);
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
draw(holder);
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
private void draw(SurfaceHolder holder){
Canvas canvas = holder.lockCanvas();
canvas.drawColor(Color.GRAY);
canvas.drawRect(150, 200, 200, 250, p);
holder.unlockCanvasAndPost(canvas);
}
}
解説
SurfaceViewのコールバックを受け取るクラスです。コールバックを受け取るクラスはSurfaceHolder.Callback インターフェイスを実装する必要があるため、"implements SurfaceHolder.Callback"を記述します。
surfaceDestroyed, surfaceChanged, surfaceChangedがSurfaceViewの画面作成や画面描画の際に呼び出されるコールバックメソッドになります。
MainActivity.java
package com.iPentec.simplesurfaceview2;
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;
}
}
実行結果
プロジェクトを実行します。下図の画面が実行結果として表示されます。
補足
SurfaceView単体ではマルチスレッドはサポートされていないため、draw()メソッドを下記のコードにした場合、アプリケーションがロックします。ロックしないようにするには描画処理を別スレッドにします。描画部分を別スレッドにするコードは
こちらの記事を参照してください。
private void draw(SurfaceHolder holder){
int cx=10;
int cy=10;
while (true){
cx++;
cy++;
Canvas canvas = holder.lockCanvas();
canvas.drawColor(Color.GRAY);
canvas.drawCircle(cx, cy, 25, p);
holder.unlockCanvasAndPost(canvas);
}
}
著者
iPentecのプログラマー、最近はAIの積極的な活用にも取り組み中。
とっても恥ずかしがり。
最終更新日: 2024-01-04
作成日: 2013-05-16