スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

レイアウトxmlでSurfaceViewを使用する

はじめに


久々の投稿です。以前、SurfaceViewについての記事を投稿しましたが、その際はSurfaceViewを画面全体に使用しており、レイアウトにxmlファイルを使用していませんでした。しかし、androidを開発する場合は、レイアウトはxmlファイルにまとめた方が何かと便利ですので、今回はxmlファイルを使用してSurfaceViewを画面上にレイアウトしてみたいと思います。


ポイント


今回のポイントは、SurfaceViewのためのコールバックをどうやって登録するか、です。そこさえ理解できれば、後は以前の記事と同じです。


プロジェクトの新規作成


いつものようにEclipseを起動して、新規プロジェクトを作成します。「ファイル」→「新規」→「Androidプロジェクト」を選択して、「新規Androidプロジェクト」ウィンドウを表示させます。そして以下を設定します。


プロジェクト名:SampleSurView


ビルド・ターゲット:Android 1.6


アプリケーション名:Sample Sur View


パッケージ名:jp.sample.SampleSurView


Create Activity:SampleSurView


リソースレイアウトの修正


以前、SurfaceViewを使用したサンプルでは、リソースレイアウトを使用していませんでした。しかし、今回はxmlファイルを使用してSurfaceViewをレイアウトします。


<?xml version="1.0" encoding="utf-8"?>

<TableLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/TableLayoutMain">


<!-- メイン領域:SurfaceViewを使用する -->
<SurfaceView
android:id="@+id/SurfaceViewMain"
android:layout_width="fill_parent"
android:layout_height="100px">

</SurfaceView>

<!-- ボタン領域 -->
<TableRow
android:id="@+id/TableRowMenu"
android:layout_width="fill_parent"
android:layout_height="wrap_content">

<Button
android:id="@+id/ButtonA"
android:text="A">

</Button>
<Button
android:id="@+id/ButtonB"
android:text="B">

</Button>
<Button
android:id="@+id/ButtonC"
android:text="C">

</Button>
<Button
android:id="@+id/ButtonD"
android:text="D">

</Button>
</TableRow>
</TableLayout>

今回はシンプルなレイアウトです。画面上部にSurfaceViewを配置し、その下にボタンを4つ配置しています。これらのビューをうまく配置するために、TableLayoutも使用しています。実際にこれを実行すると、以下のような画面になります。


20100103_article1

レイアウトは以上になります。後はSurfaceViewに対してコールバックを登録すればOKです。


ソースコードの修正


今回はソースコードを2つに分けます。1つは普段生成するメインのアクティビティのソースコード、もう1つはSurfaceView用のソースコードです。まずは、SurfaceView用のソースコードから掲載します。


「MainSurfaceView.java」


import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class MainSurfaceView implements SurfaceHolder.Callback, Runnable {
private SurfaceHolder holder;
private static final String LOG = "MainSurfaceView";

// コンストラクタ
public MainSurfaceView(Context context, SurfaceView sv) {
holder = sv.getHolder();
holder.addCallback(this);
}

@Override
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
Log.d(LOG, "surfaceChanged");
}

@Override
public void surfaceCreated(SurfaceHolder arg0) {
Log.d(LOG, "surfaceCreated");

Canvas canvas = arg0.lockCanvas();
canvas.drawColor(Color.BLACK);

// canvasを使用してSurfaceViewに描画する
arg0.unlockCanvasAndPost(canvas);
}

@Override
public void surfaceDestroyed(SurfaceHolder arg0) {
Log.d(LOG, "surfaceDestroyed");
}

@Override
public void run() {
Log.d(LOG, "run");
}
}

上記コードの一番のポイントは、コンストラクタの部分です。引数でSurfaceViewクラスのインスタンスをもらい、そこからgetHolderメソッドでSurfaceHolderを取得し、addCallbackメソッドで自クラスをコールバックとして登録します。これでOK。後は、上記MainSurfaceViewクラスをインスタンス化する時に、引数でSurfaceViewクラスのインスタンスを渡せば、SurfaceViewを使用することができます。


なお、MainSurfaceViewクラスの各メソッド(surfaceChanged, surfaceCreated, surfaceDestoryed, run)に、それぞれSurfaceViewを使用する際に実行したいコードを記述すれば、所望の動作をSurfaceViewに行わせることができます。今回はログを表示するのみ。




残りはメインのアクティビティのソースコードです。こちらのアクティビティから上記MainSurfaceViewクラスをインスタンス化します。


「SampleSurView.java」


import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.View;
import android.widget.Button;

public class SampleSurView extends Activity {
private SurfaceView mSvMain;
private MainSurfaceView mMainDrawArea;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);

// SurfaceViewを参照
mSvMain = (SurfaceView)findViewById(R.id.SurfaceViewMain);

// 作成したMainSurfaceViewクラスをインスタンス化
mMainDrawArea = new MainSurfaceView(this, mSvMain);
}
}

ポイントはonCreateメソッドの中の最後の二行です。まずはリソースレイアウトにて定義したSurfaceViewをfindViewByIdメソッドによって参照します。これはmSvMainというメンバに保持しておきます。次に、mSvMainをMainSurfaceViewクラスをインスタンス化する際の第二引数に渡します。すると、MainSurfaceViewクラスのコンストラクタ内で、第二引数で渡されたインスタンスを使用して、MainSurfaceViewクラスをSurfaceViewを使用するためのコールバックとして登録します(MainSurfaceView.javaファイル参照)。これだけです。


実行結果


今回は目に見える動作は何も実行していませんので、実行結果は特にありません。


おわりに


今回はSurfaceViewをリソースレイアウトxmlファイルで使用してみました。Androidアプリを開発する場合はxmlファイルでレイアウトをいじる場合が多いと思いますので、今回の例のようにSurfaceViewを使用する場合もリソースレイアウトでレイアウトする場合が多いと思います。



スポンサーサイト

テーマ : プログラミング
ジャンル : コンピュータ

SurfaceViewの使い方4:ユーザがタッチできるようにする

はじめに


前回の記事では、ボールをSurfaceViewに描画して、画面内を跳ね返りながら動かすプログラムを作成しました。ただ、これでは勝手にボールが動くだけのプログラムなので、ユーザがいろいろ操作できるようにしたいと思います。


基本的に、Androidでユーザがタッチパネルにタッチしたことを受け取るためには、onTouchEventメソッドをOverrideしてやることで実現できます。また、キー入力を受け取るためには、onKeyDownやonKeyUpメソッドをOverrideしてやることで実現できます。


そして、いろいろ調べてみると、SurfaceViewクラスでも、onTouchEventなどのメソッドを用いてタッチイベントなどを拾えるそうです。SurfaceViewクラスを継承したクラスで、onTouchEventメソッドをOverrideすることで、タッチイベントを受け取る事ができます。今回は、このonTouchEventをOverrideして、ユーザが画面をタッチしたら、ボールの移動する方向を変えるようなプログラムを作成したいと思います。


プロジェクトの新規作成


いつものようにEclipseを起動して、新規プロジェクトを作成します。「ファイル」→「新規」→「Androidプロジェクト」を選択して、「新規Androidプロジェクト」ウィンドウを表示させます。そして以下を設定します(前回までと同じですね)。


  • プロジェクト名:SampleSurViewCycle

  • ビルド・ターゲット:Android 1.6

  • アプリケーション名:Sample Surface View Cycle

  • パッケージ名:jp.sample.SampleSurViewCycle

  • Create Activity:SampleSurViewCycle

  • リソースレイアウトの修正


    今回もリソースレイアウトは使用しません。SurfaceViewクラスを継承したクラスを用いますので。


    ソースコードの修正


    今回修正するコードは、前回の記事のSampleSurfaceViewCycle.javaをベースにして、onTouchEventメソッドのみをOverrideして追加します。コードの全体は以下です。


    package jp.sample.SampleSurViewCycle;

    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.view.SurfaceHolder;
    import android.view.SurfaceView;
    import android.view.MotionEvent;;

    public class SampleSurViewCycle extends Activity {
    // スレッドクラス
    Thread mainLoop = null;
    // 描画用
    Paint paint = null;

    // SurfaceViewを描画するクラス
    class DrawSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable{
    // 円のX,Y座標
    private int circleX = 0;
    private int circleY = 0;
    // 円の移動量
    private int circleVx = 5;
    private int circleVy = 5;

    public DrawSurfaceView(Context context) {
    super(context);
    // SurfaceView描画に用いるコールバックを登録する。
    getHolder().addCallback(this);
    // 描画用の準備
    paint = new Paint();
    paint.setColor(Color.WHITE);
    // スレッド開始
    mainLoop = new Thread(this);
    mainLoop.start();
    }

    // タッチイベントを処理するためOverrideする
    @Override
    public boolean onTouchEvent(MotionEvent event) {
    // 移動する方向を反転させる
    // onTouchEventでは、以下の動きをとらえる事ができる
    // [ACTION_DOWN] [ACTION_UP] [ACTION_MOVE] [ACTION_CANCEL]
    // 今回はACTION_DOWN(タッチパネルが押されたとき)に、ボールの動きを反転させます
    switch (event.getAction())
    {
    case MotionEvent.ACTION_DOWN:
    circleVx *= -1;
    circleVy *= -1;
    break;
    default:
    break;
    }
    return true;
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
    int height) {
    // TODO 今回は何もしない。
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
    // SurfaceView生成時に呼び出されるメソッド。
    // 今はとりあえず背景を白にするだけ。
    Canvas canvas = holder.lockCanvas();
    canvas.drawColor(Color.BLACK);
    holder.unlockCanvasAndPost(canvas);
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    // TODO 今回は何もしない。
    }

    @Override
    public void run() {
    // Runnableインターフェースをimplementsしているので、runメソッドを実装する
    // これは、Threadクラスのコンストラクタに渡すために用いる。
    while (true) {
    Canvas canvas = getHolder().lockCanvas();
    if (canvas != null)
    {
    canvas.drawColor(Color.BLACK);
    // 円を描画する
    canvas.drawCircle(circleX, circleY, 10, paint);
    getHolder().unlockCanvasAndPost(canvas);
    // 円の座標を移動させる
    circleX += circleVx;
    circleY += circleVy;
    // 画面の領域を超えた?
    if (circleX < 0 || getWidth() < circleX) circleVx *= -1;
    if (circleY < 0 || getHeight() < circleY) circleVy *= -1;
    }
    }
    }

    }

    // アクティビティが生成されたときに呼び出されるメソッド
    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(new DrawSurfaceView(this));
    }

    @Override
    public void onDestroy() {
    super.onDestroy();
    Thread.interrupted();
    }
    }

    コードが長くなってしまいましたが、前回の記事と異なるのはonTouchEventメソッドの部分だけです。onTouchEventメソッドを、SurfaceViewクラスを継承したDrawSurfaceViewクラス内でOverrideします。すると、SurfaceView上でタッチした場合に、そのイベントを拾えるようになります。


    onTouchEventメソッドでは、ユーザがどのようなアクションをしたかを判別する事ができます。MotionEvent.ACTION_DOWN・・・タッチしたとき、MotionEvent.ACTION_UP・・・タッチを離したとき、MotionEvent.ACTION_MOVE・・・タッチしながら移動させているとき、等。他にもいろいろイベントを拾えるようです。詳しくは、MotionEvent | Androidを参照すると良いと思います。


    実行結果


    SurfaceView_06_onTouchEvent_01.png

    まずは起動直後。白いボールが画面左上から右下へ移動していきます。前回はこのまま動き続けるだけですが、今回はタッチすると動きが反転するので、エミュレータ上でタッチ(正確にはマウスでクリック)してみます。


    SurfaceView_07_onTouchEvent_02.png

    静止画なので、ボールの動きが反転しているかどうか分かりませんが、上記コードを実行するとうまく動いているようです。もう一度タッチすると、またボールの動きが反転します。これで今回の目的は達成しました。


    おわりに


    今回はSurfaceViewでユーザのタッチイベントを受け付けるようにしました。少しだけ、前回よりゲームチックになったように思います(まだまだしょぼいですが)。ただし、これだけでは、まだまだ使えるレベルではないので、次回はよりゲームチックな要素を取り入れたサンプルを作りたいと思います。





    テーマ : プログラミング
    ジャンル : コンピュータ

    SurfaceViewの使い方3:ボールを描画して動かす

    はじめに


    前回の記事では、SurfaceViewに対して、定期的にテキストを描画してみました。今回はよりゲームっぽさを出すために、ボール(というか、単なるCircle)をSurfaceView上に描画して、動かしてみます。また、少しだけ高度に動かすために、画面の端に来たら跳ね返るようにしたいと思います。


    ボールを描画するために、今回はCanvasクラスのdrawCircleメソッドを使用します。このメソッドは、引数としてX,Y座標と半径、Paintクラスのインスタンスを受け取ると、その情報に従ってCanvas上に円を描画します。このメソッドを、前回の記事のコードのrunメソッド内で呼び出せば、定期的に円を描画できます。後は、引数に与えるX,Y座標をちょっとずつ増やすor減らす処理を行えば、あたかも移動しているように見えます。


    プロジェクトの新規作成


    いつものようにEclipseを起動して、新規プロジェクトを作成します。「ファイル」→「新規」→「Androidプロジェクト」を選択して、「新規Androidプロジェクト」ウィンドウを表示させます。そして以下を設定します。



    • プロジェクト名:SampleSurViewCycle

    • ビルド・ターゲット:Android 1.6

    • アプリケーション名:Sample Surface View Cycle

    • パッケージ名:jp.sample.SampleSurViewCycle

    • Create Activity:SampleSurViewCycle


    リソースレイアウトの修正


    今回もリソースレイアウトmain.xmlファイルは使用しないため、修正は無しです。


    ソースコードの修正


    今回は、前回の記事で用いたソースコードをベースとします。まずは、全体のソースコード。


    package jp.sample.SampleSurViewCycle;

    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.view.SurfaceHolder;
    import android.view.SurfaceView;

    public class SampleSurViewCycle extends Activity {
    // スレッドクラス
    Thread mainLoop = null;
    // 描画用
    Paint paint = null;

    // SurfaceViewを描画するクラス
    class DrawSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable{
    // 円のX,Y座標
    private int circleX = 0;
    private int circleY = 0;
    // 円の移動量
    private int circleVx = 5;
    private int circleVy = 5;

    public DrawSurfaceView(Context context) {
    super(context);
    // SurfaceView描画に用いるコールバックを登録する。
    getHolder().addCallback(this);
    // 描画用の準備
    paint = new Paint();
    paint.setColor(Color.WHITE);
    // スレッド開始
    mainLoop = new Thread(this);
    mainLoop.start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
    int height) {
    // TODO 今回は何もしない。
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
    // SurfaceView生成時に呼び出されるメソッド。
    // 今はとりあえず背景を白にするだけ。
    Canvas canvas = holder.lockCanvas();
    canvas.drawColor(Color.BLACK);
    holder.unlockCanvasAndPost(canvas);
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    // TODO 今回は何もしない。
    }

    @Override
    public void run() {
    // Runnableインターフェースをimplementsしているので、runメソッドを実装する
    // これは、Threadクラスのコンストラクタに渡すために用いる。
    while (true) {
    Canvas canvas = getHolder().lockCanvas();
    if (canvas != null)
    {
    canvas.drawColor(Color.BLACK);
    // 円を描画する
    canvas.drawCircle(circleX, circleY, 10, paint);
    getHolder().unlockCanvasAndPost(canvas);
    // 円の座標を移動させる
    circleX += circleVx;
    circleY += circleVy;
    // 画面の領域を超えた?
    if (circleX < 0 || getWidth() < circleX) circleVx *= -1;
    if (circleY < 0 || getHeight() < circleY) circleVy *= -1;
    }
    }
    }

    }

    // アクティビティが生成されたときに呼び出されるメソッド
    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(new DrawSurfaceView(this));
    }

    @Override
    public void onDestroy() {
    super.onDestroy();
    Thread.interrupted();
    }
    }

    ボールの描画は、canvas.drawCircle(circleX, circleY, 10, paint);の部分で行います。単に円を単色で描画しているだけですが。


    また、ボールの移動をさせるために、ソースコードでは、circleXとcircleYを変更します。


    // 円の座標を移動させる
    circleX += circleVx;
    circleY += circleVy;

    こうしておけば、次にrunメソッドが実行されて、canvas.drawCircleメソッドが実行されたときに、前回より少し移動したボールが描画されます。


    また、このままでは画面外までボールが移動してしまうため、画面の端に到達したら、跳ね返るようにします。これは、ソースコードの


    // 画面の領域を超えた?
    if (circleX < 0 || getWidth() < circleX) circleVx *= -1;
    if (circleY < 0 || getHeight() < circleY) circleVy *= -1;

    getWidth()で画面の幅を、getHeight()で画面の高さを取得できますので、これらのメソッドを利用してcircleXとcircleYが画面内かどうかを判定しています。画面外となる場合は、ボールを移動させる方向を逆方向にします。


    実行結果


    SurfaceView_04_drawCircle.png


    実行すると、白いボールが画面左上から右下へ移動していきます。どんどん右下へ移動していき、画面端までたどり着くと、壁に跳ね返ったように移動していきます。


    なお、このプログラムを終わらせるためには、「←」ボタンを押します。


    おわりに


    SurfaceView上にボールを描いて移動させることで、けっこうゲームチックな感じになってきたと思います。ただし、このままでは単にボールが勝手に反射しているだけなので、何も楽しくありません。なので、次は、ユーザからの操作を受け付けて、ボールの動きを変えるようなプログラムを作っていきたいと思います。




    テーマ : プログラミング
    ジャンル : コンピュータ

    SurfaceViewの使い方2:定期的な描画

    はじめに


    前回の記事では、SurfaceViewをとりあえず使ってみる、というところまでやりました。ただし、SurfaceViewの本領を発揮するためには、やはり定期的に再描画を行わせないといけないと思います。今回は、SurfaceView+定期的な描画、というプログラムを作成してみます。


    いろいろなサイトをめぐってみると、SurfaceViewと描画の組み合わせで良く用いられているのは、「Runnableインターフェース」と、「Threadクラス」のようです。


    今回も、@IT「SurfaceViewならAndroidで高速描画ゲームが作れる」にあるサンプルコードを参考にしたいと思います。参考にするコードは「GameSampleWithSurfaceView.java」です。


    プロジェクトの新規作成


    いつものようにEclipseを起動して、新規プロジェクトを作成します。「ファイル」→「新規」→「Androidプロジェクト」を選択して、「新規Androidプロジェクト」ウィンドウを表示させます。そして以下を設定します。



    • プロジェクト名:SampleSurViewCycle

    • ビルド・ターゲット:Android 1.6

    • アプリケーション名:Sample Surface View Cycle

    • パッケージ名:jp.sample.SampleSurViewCycle

    • Create Activity:SampleSurViewCycle


    リソースレイアウトの修正


    今回もリソースレイアウトmain.xmlファイルは使用しないため、修正は無しです。


    ソースコードの修正


    ソースコードSampleSurViewCycle.javaファイルを修正していきます。基本的には前回の記事のコードをベースとしていきます(SurfaceViewを使用するのは前回と一緒なので)。今回は、そのコードに、定期的に描画するためのコードのみを追加したいと思います。まずは、ソースコードの全体を以下に示します。


    package jp.sample.SampleSurViewCycle;

    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.view.SurfaceHolder;
    import android.view.SurfaceView;

    public class SampleSurViewCycle extends Activity {
    // スレッドクラス
    Thread mainLoop = null;
    // 描画用
    Paint paint = null;
    // デバッグ用
    int count = 0;

    // SurfaceViewを描画するクラス
    class DrawSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable{

    public DrawSurfaceView(Context context) {
    super(context);
    // コンストラクタ。SurfaceView描画に用いるコールバックを登録する。
    getHolder().addCallback(this);
    // 描画用の準備
    paint = new Paint();
    paint.setColor(Color.BLUE);
    paint.setAntiAlias(true);
    paint.setTextSize(24);
    // 加えて、スレッドを開始する
    // 引数にはDrawSurfaceView、自分自身のインスタンスを渡す(Runnableをimplementsしていないといけない)。
    mainLoop = new Thread(this);
    // スレッドスタート。そうすると、runメソッドが実行される。
    mainLoop.start();
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
    int height) {
    // TODO 今回は何もしない。
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
    // SurfaceView生成時に呼び出されるメソッド。
    // 今はとりあえず背景を白にするだけ。
    Canvas canvas = holder.lockCanvas();
    canvas.drawColor(Color.WHITE);
    holder.unlockCanvasAndPost(canvas);
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    // TODO 今回は何もしない。
    }

    @Override
    public void run() {
    // Runnableインターフェースをimplementsしているので、runメソッドを実装する
    // これは、Threadクラスのコンストラクタに渡すために用いる。
    while (true) {
    Canvas canvas = getHolder().lockCanvas();
    if (canvas != null)
    {
    canvas.drawColor(Color.WHITE);
    canvas.drawText("count = " + count, 0, paint.getTextSize(), paint);
    count++;
    getHolder().unlockCanvasAndPost(canvas);
    }
    if (count == 100) {
    break;
    }
    }
    }

    }

    // アクティビティが生成されたときに呼び出されるメソッド
    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(new DrawSurfaceView(this));
    }

    @Override
    public void onDestroy() {
    super.onDestroy();
    Thread.interrupted();
    }
    }

    ポイント1として、DrawSurfaceViewクラスでRunnableインターフェースをimplementsしている点です。このインターフェースをimplementsすると、runというメソッドを実装します。これは、後述するThreadクラスをインスタンス化して、startさせると呼び出されるメソッドです。ここで、定期的に描画するコードを記載すると、SurfaceViewに定期的な描画が可能となります。リアルタイムOSで言うタスクのコードをrunメソッドに記載すれば良いイメージ?


    なので、上記のコードのrunメソッドでは、while (true) で無限ループさせています。whileループ内では、PaintクラスとCanvasクラスのインスタンスを用いて、テキストをSurfaceViewに描画しています。ただし、同じテキストだと書き換えられたことが分からないので、countという変数をインクリメントさせて表示させています。


    後は、このrunメソッドを呼び出すスレッドを生成するだけです。これは、Threadクラスをインスタンス化して、startメソッドを呼び出すことで実現できます。インスタンス化するときに、コンストラクタの引数にRunnableインターフェースをimplementsしたクラスのインスタンスを渡すということです。コードでは、


    mainLoop = new Thread(this);

    の部分です。その後、mainLoop.start();を実行すると、runメソッドが呼び出されます。


    実行結果


    SurfaceView_02_runnable.png


    今回は、定期的にカウントアップしたcount変数の値をSurfaceViewに表示させています(0~99の間)。


    おわりに


    今回は、SurfaceViewを用いた定期的な描画を行うサンプルプログラムを作成してみました。今回は何も考えず、定期的にテキストを描画するだけですが、runメソッドの中をいろいろ書き換えれば、画像を表示したり、それを移動させたり、あるいはキーボードイベントやタッチイベントに応じて画像を移動させることもできると思います。次は、そのあたりのプログラムを作りたいと思います。


    参考サイト





    テーマ : プログラミング
    ジャンル : コンピュータ

    SurfaceViewの使い方1

    はじめに


    今回からは、SurfaceViewクラスについて、調べていきます。SurfaceViewクラスは、@IT「SurfaceViewならAndroidで高速描画ゲームが作れる」にもあるように、ゲームアプリなどで、定期的に描画が必要となる場合に効果を発揮するクラスです。


    今回は、まず@IT「SurfaceViewならAndroidで高速描画ゲームが作れる」にあるサンプルコード(zip圧縮したもの)を利用しようと思います。


    と思いましたが、このサンプルコードには、大変親切なことにいろいろなサンプルをListViewで選択して試すことができるようで、SurfaceView導入編としては敷居が高いかも・・・と思ったので、やはりシンプルに最初から順々にやっていきます。ただし、@ITのサンプルコードは多いに参考させていただきます。参考とするコードはHello.javaです。


    プロジェクトの新規作成


    いつものようにEclipseを起動して、新規プロジェクトを作成します。「ファイル」→「新規」→「Androidプロジェクト」を選択して、「新規Androidプロジェクト」ウィンドウを表示させます。そして以下を設定します。



    • プロジェクト名:SampleSurView

    • ビルド・ターゲット:Android 1.6

    • アプリケーション名:Sample Surface View

    • パッケージ名:jp.sample.SampleSurView

    • Create Activity:SampleSurView


    リソースレイアウト(XML)の修正


    今回はリソースレイアウトを使用しないため、main.xmlファイルはデフォルトのままでOK。


    ソースコードの修正


    方針


    SampleSurView.javaファイルをいじくっていきます。今回SurfaceViewを使用するために、メインクラスであるSampleSurViewクラスのサブクラスとして、DrawSurfaceViewクラスを作ることにします(コードの全体は以下)。このサブクラスがSurfaceViewを作って描画します。


    package jp.sample.SampleSurView;

    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.SurfaceHolder;
    import android.view.SurfaceView;

    public class SampleSurView extends Activity {
    // SurfaceViewを継承したサブクラス
    class DrawSurfaceView extends SurfaceView implements SurfaceHolder.Callback {

    public DrawSurfaceView(Context context) {
    // コンストラクタ
    super(context);
    // SurfaceHolderを取得するために、getHolderメソッドを呼び出す
    // そして、コールバックを登録するために、addCallbackメソッドも呼び出す。
    getHolder().addCallback(this);
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
    int height) {
    // SurfaceViewのサイズなどが変更されたときに呼び出されるメソッド。
    // 今回は何もしない(ログ表示のみ)。
    Log.d("SampleSurView", "surfaceChanged called.");
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
    // SurfaceViewが最初に生成されたときに呼び出されるメソッド
    Log.d("SampleSurView", "surfaceCreated called.");

    // SurfaceHolderからCanvasのインスタンスを取得する
    Canvas canvas = holder.lockCanvas();
    // Paintクラスのインスタンスを作る。これは、描画するときに使用する
    // 色は青、アンチエイリアスON、テキストサイズ24
    Paint paint = new Paint();
    paint.setColor(Color.BLUE);
    paint.setAntiAlias(true);
    paint.setTextSize(24);
    // Canvasの背景色を白で塗る
    canvas.drawColor(Color.WHITE);

    // Canvasに文字を書く。ここでPaintクラスのインスタンスを用いる。
    // つまり、青色でテキストサイズが24でアンチエイリアスのかかった「Sample Text」を描画する
    canvas.drawText("Sample Test", 0, paint.getTextSize(), paint);

    // 描画が終わったら呼び出すメソッド。
    holder.unlockCanvasAndPost(canvas);
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
    // SurfaceViewが破棄されるときに呼び出されるメソッド
    // 今回は実装しない。
    Log.d("SampleSurView", "surfaceDestroyed");
    }

    }

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // *注意:ここはレイアウトリソースであるR.layout.mainを使用せず、
    //     SurfaceViewを継承したサブクラスDrawSurfaceViewのインスタンスを渡す。
    setContentView(new DrawSurfaceView(this));
    }
    }

    ポイント


    このサブクラスは、SurfaceViewを使用するために、SurfaceViewクラスを継承(extends)します。また、SurfaceViewを使用するために、SurfaceHolder.Callbackクラスのインターフェースを実装しないといけないため、implementsします。


    また、SurfaceHolder.Callbackクラスをimplementsすると、3つのメソッドsurfaceChanged、surfaceCreated、surfaceDestroyedを実装しなければなりません。今回のサンプルでは、surfaceCreatedメソッド、つまりSurfaceViewが生成されたときに呼び出されるメソッド、のみ実装しています。ここでは、SurfaceViewを白で塗りつぶして、「Sample Text」というテキストを青色で表示します。


    最後に重要なポイントとしては、SampleSurViewクラスのonCreateメソッドでsetContentViewメソッドを呼んでいますが、通常はR.layout.mainというようにリソースレイアウトを指定します。しかし今回は、DrawSurfaceViewクラスのインスタンスを渡しています。今の私にはよく分かりませんが、SurfaceViewを使用する際はこれが一般的だそうです(by @IT)。


    実行結果


    エミュレータで起動すると、アプリが起動して以下のような実行結果となります。うまく表示できました。


    SurfaceView_01_showText.png

    一応アンチエイリアスはONにしていますが、見た目汚いように思います。テキストを表示するときはBMPファイルなどにしたほうが良いかも。


    おわりに


    今回は起動時に一度だけ描画するのみなので、SurfaceViewのありがたみがまったく分かりませんでした。次は定期的に描画するプログラムを作成してみたいと思います。


    [メモ]最初、Android SDK 1.6でSurfaceViewを使用したコードを実行すると、なぜか「NullPointerException」例外が発生して実行できませんでした。いろいろ調べてみると、どうやらEclipse 64bit版をインストールしていたことが原因だったようでした。アンインストールして32bit版Eclipseをインストールすると、うまく動いたので・・・64bitアプリというのは、何かと問題があるようです。





    テーマ : プログラミング
    ジャンル : コンピュータ

    プロフィール

    sepiablue

    Author:sepiablue
    組込みソフトウェアエンジニアやってます。普段はC言語使い。
    趣味はプログラミング、京都旅行で神社巡り。
    AndroidアプリをMacで開発中。

    最新記事
    スポンサードリンク
    スポンサードリンク
    月別アーカイブ
    カテゴリ
    検索フォーム
    RSSリンクの表示
    リンク
    QRコード
    QRコード
    上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。