XMLレイアウトでSurfaceViewを用いる - Android
XMLレイアウトでSurfaceViewを用いる手順を紹介します。
概要
こちらの記事では、コードでSurfaceViewを生成しましたが、画面の一部にSurfaceViewを配置する場合はXMLレイアウトを用いたほうが便利です。この記事ではXMLレイアウトを用いた場合にSurfaceViewを画面に配置するコードを紹介します。
プロジェクトの作成
Android アプリケーションプロジェクトを作成します。
[New Android Application]ダイアログボックスが表示されますので、以下を設定します。
- Application Name: "SimpleSurfaceViewXML"
- Project Name: "SimpleSurfaceViewXML"
- Package Name: "com.iPentec.simplesurfaceviewxml"
- Minimum Required SDK: "API 8: Android 2.2 (Froyo)"
- Target SDK: "API 17: Android 4.2 (Jelly Bean)"
- Compile With: "API 17: Android 4.2 (Jelly Bean)"
- Theme: "Holo Light with Dark Action Bar"
UIの作成
レイアウトを変更します。
レイアウトXMLファイルを編集して下記のコードを記述します。
<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/TableLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<SurfaceView
android:id="@+id/SurfaceViewMain"
android:layout_width="fill_parent"
android:layout_height="200dp">
</SurfaceView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />
</TableLayout>
デザイナの画面では数の状態になります。
コード
下記のコードを記述します。
package com.ipentec.simplesurfaceviewxml;
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.SurfaceView;
import android.widget.Button;
public class MainActivity extends Activity {
private SurfaceView surfaceView;
private MainSurfaceView mainSurfaceView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
surfaceView = (SurfaceView)findViewById(R.id.SurfaceViewMain);
mainSurfaceView = new MainSurfaceView(this, surfaceView);
}
@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;
}
}
解説
onCreateメソッド内の
surfaceView = (SurfaceView)findViewById(R.id.SurfaceViewMain);
mainSurfaceView = new MainSurfaceView(this, surfaceView);
が追記部分となります。1行目はSurfaceViewのリソースIDを用いてfindViewById()メソッドを呼び出し、SurfaceViewオブジェクトを取得します。2行目はカスタム化したMainSurfaceViewのインスタンスを作成します。MainSurfaceViewのコンストラクタの第二引数にSurfaceViewのオブジェクトを与えます。
package com.ipentec.simplesurfaceviewxml;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.Paint;
public class MainSurfaceView implements SurfaceHolder.Callback, Runnable {
private SurfaceHolder holder;
private static final String TAG = "MainSurfaceView";
private Thread thread;
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(TAG, "surfaceChanged");
}
@Override
public void surfaceCreated(SurfaceHolder arg0) {
Log.d(TAG, "surfaceCreated");
Canvas canvas = arg0.lockCanvas();
canvas.drawColor(Color.BLACK);
arg0.unlockCanvasAndPost(canvas);
}
@Override
public void surfaceDestroyed(SurfaceHolder arg0) {
Log.d(TAG, "surfaceDestroyed");
thread=null;
}
@Override
public void run() {
Log.d(TAG, "run");
}
}
解説
SurfaceHolder.Callback, Runnableを継承したクラスの場合コンストラクタ、surfaceChanged, surfaceCreated, surfaceDestroyed, runのメソッドのオーバーライドが必要なため、各メソッドを実装しています。
実行結果
プロジェクトを実行します。数の画面が表示されます。まだ何も描画されない状態です。
描画のコードを記述する
画面描画のコードを記述します。MainSurfaceView.javaを下記のコードを記述します。
package com.ipentec.simplesurfaceviewxml;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.Paint;
public class MainSurfaceView implements SurfaceHolder.Callback, Runnable {
private SurfaceHolder holder;
private static final String TAG = "MainSurfaceView";
private Thread thread;
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(TAG, "surfaceChanged");
thread = new Thread(this);
thread.start();
}
@Override
public void surfaceCreated(SurfaceHolder arg0) {
Log.d(TAG, "surfaceCreated");
Canvas canvas = arg0.lockCanvas();
canvas.drawColor(Color.BLACK);
arg0.unlockCanvasAndPost(canvas);
}
@Override
public void surfaceDestroyed(SurfaceHolder arg0) {
Log.d(TAG, "surfaceDestroyed");
thread=null;
}
@Override
public void run() {
Log.d(TAG, "run");
while (thread != null) {
doDraw(holder);
}
}
private void doDraw(SurfaceHolder holder) {
Canvas canvas = holder.lockCanvas();
if (canvas != null){
Paint paint = new Paint();
paint.setColor(Color.YELLOW);
canvas.drawColor(Color.BLACK);
Path path = new Path();
float theta = (float)(Math.PI * 72 / 180);
float r = 50f;
PointF center = new PointF(200f, 80f);
float dx1 = (float)(r*Math.sin(theta));
float dx2 = (float)(r*Math.sin(2*theta));
float dy1 = (float)(r*Math.cos(theta));
float dy2 = (float)(r*Math.cos(2*theta));
path.moveTo(center.x, center.y-r);
path.lineTo(center.x-dx2, center.y-dy2);
path.lineTo(center.x+dx1, center.y-dy1);
path.lineTo(center.x-dx1, center.y-dy1);
path.lineTo(center.x+dx2, center.y-dy2);
path.lineTo(center.x, center.y-r);
canvas.drawPath(path, paint);
holder.unlockCanvasAndPost(canvas);
}
}
}
解説
スレッドの作成と解放
スレッドの作成と解放のコードは下記になります。
surfaceChangedメソッドに
thread = new Thread(this);
thread.start();
を追記します。
また、surfaceDestroyedメソッドに
thread=null
を追記します。
描画
下記が描画部のコードになります。
runメソッドに
while (thread != null) {
doDraw(holder);
}
を記述します。
doDrawメソッドを記述します。キャンバスをロックし、星形を描画するコードを記述します。
private void doDraw(SurfaceHolder holder) {
Canvas canvas = holder.lockCanvas();
if (canvas != null){
Paint paint = new Paint();
paint.setColor(Color.YELLOW);
canvas.drawColor(Color.BLACK);
Path path = new Path();
float theta = (float)(Math.PI * 72 / 180);
float r = 50f;
PointF center = new PointF(200f, 80f);
float dx1 = (float)(r*Math.sin(theta));
float dx2 = (float)(r*Math.sin(2*theta));
float dy1 = (float)(r*Math.cos(theta));
float dy2 = (float)(r*Math.cos(2*theta));
path.moveTo(center.x, center.y-r);
path.lineTo(center.x-dx2, center.y-dy2);
path.lineTo(center.x+dx1, center.y-dy1);
path.lineTo(center.x-dx1, center.y-dy1);
path.lineTo(center.x+dx2, center.y-dy2);
path.lineTo(center.x, center.y-r);
canvas.drawPath(path, paint);
holder.unlockCanvasAndPost(canvas);
}
}
実行結果
プロジェクトを実行します。星形が描画されました。
著者
iPentecのプログラマー、最近はAIの積極的な活用にも取り組み中。
とっても恥ずかしがり。
最終更新日: 2024-01-04
作成日: 2013-04-05