Android アプリ開発 「MATRIX」

Androidアプリの開発に役立つサンプル集



レイアウトXML に配置した SurfaceView 内でカウンターを動かしてみよう

今回は SurfaceView のサンプル

今回はレイアウトXML の一部に SurfaceView を配置し、その SurfaceView の中でカンターを動かしてみたいと思います。MainActivity と SurfaceView の関係が若干わかりにくいかもしれませんが、 一度覚えてしまえば楽に実装できるようになると思います。

サンプルコード①(activity_main.xml

使用するレイアウトは、Android Stuido が自動で生成したレイアウトXMLに SurfaceView を追加しただけのシンプルなものです。高さと幅は自由に確保してください。

<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="sample.mysurfacetest.MainActivity">

<SurfaceView
android:id="@+id/surfaceView"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
app:layout_constraintBottom_toTopOf="@+id/textView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="textView"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />

</android.support.constraint.ConstraintLayout>

※デザインビューで見るとこんな感じになります。

f:id:vw-dsg:20171222093106p:plain

サンプルコード②(MainActivity.class)

レイアウト(activity_main)は普通に読み込みます。その後、レイアウトXML に配置した SurfaceView を取得して、 それを context と一緒に MySurfaceView.class に渡します。

public class MainActivity extends AppCompatActivity {

//オブジェクト・変数を用意
private TextView textView;
private SurfaceView mSurfaceView;
private MySurfaceView mSfV;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

//レイアウトxmlをセット
setContentView(R.layout.activity_main);

//レイアウトXMLから textView を取得する
textView = (TextView)findViewById(R.id.textView);
//文字色をグリーンに指定
textView.setTextColor(Color.BLUE);
//文字サイズを50に指定
textView.setTextSize(30);
//文字をセットして表示
textView.setText("SurfaceView カウンター");

//レイアウトXMLから SurfaceView を取得
mSurfaceView = (SurfaceView)findViewById(R.id.surfaceView);
//MySurfaceView.java context mSurfaceView を送って実体化する
mSfV = new MySurfaceView(this, mSurfaceView);
}
}

サンプルコード③(MySurfaceView.class)

SurfaceView を継承し、SurfaceHolder のコールバックと Runnable のインターフェースを実装します。重要ポイイントは、コンストラクターが受け取る引数に「SurfaceHolder sv」を追加するところです。これを追加しないと MainActivity から送られてくる SurfaceView を受け取ることができず、レイアウトXMLに配置した SurfaceView にアクセスすることができません。

public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable {

//オブジェクト・変数を用意
private SurfaceHolder holder1;
private Thread thread;
private Canvas canvas;
private Paint paint;
private int count;

//コンストラクターで初期化(ここが最初に実行される)
public MySurfaceView(Context context, SurfaceView sv) {
super(context);

//サーフェースフォルダーを取得
holder1 = sv.getHolder();
//取得したサーフェースホルダーにコールバック機能を追加
holder1.addCallback(this);
//別スレッドを用意
thread = new Thread(this);
//count という名前の変数に 0 をセット
count = 0;
}

@Override
public void surfaceCreated(SurfaceHolder holder2) {
//SurfaceView が作られると同時にスレッドをスタート
thread.start();
}

@Override
public void surfaceChanged(SurfaceHolder holder3, int format, int width, int height) {
//SurfaceView が変更されると実行されるメソッド
//今回はここを使用しませんがこれが無いとエラーになるためとりあえす存在している
}

@Override
public void surfaceDestroyed(SurfaceHolder holder4) {
//SurfaceView が破棄される時にスレッドを停止
thread = null;
}

@Override
public void run() { //run() はスレッドが開始されると実行される

//SurfaceView に表示する文字の各詳細を paint で設定している
paint = new Paint();
paint.setTextSize(80);
paint.setColor(Color.WHITE);
paint.setAntiAlias(true);

//スレッドが存在する限りループする
while (thread != null) {

//ダブルバッファリングを準備
canvas = holder1.lockCanvas();
//用意しておいた canvas に文字色と表示文字を設定
canvas.drawColor(Color.RED);
canvas.drawText("カウント" + count + " 回",10,80,paint);
//ここで SurfaceView canvas を描画する
holder1.unlockCanvasAndPost(canvas);

//カウントを1アップ
count += 1;
}
}

<結果>

画面の一部に SurfaceView が表示され、その中でカウンターが動作しました。

f:id:vw-dsg:20171222090107p:plainEND