LoginSignup
4
5

More than 5 years have passed since last update.

AndroidでSurfaceViewを使ってみた

Posted at

SurfaceViewをKotlinで実装してみました。

目的

  • SurfaceViewを使ってみる。
  • Kotlinを使ってみる。

SurfaceViewのポイント

  • SurfaceHolderを介して操作する。
  • メインスレッド以外から描画可能。
  • SurfaceHolder.CallbackのsurfaceCreated()からsurfaceDestroyed()のみ描画可能

実装

今回は、画面全体をSurfaceViewにしてみます。

activity_surface_view.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout 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=".SurfaceViewActivity">

    <SurfaceView
        android:id="@+id/surfaceView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</android.support.design.widget.CoordinatorLayout>

Kotlinで空のActivityを作成し、レイアウトを読み込みます。

SurfaceViewActivity.kt
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.view.SurfaceView

class SurfaceViewActivity : AppCompatActivity() {

    private var mainSurfaceView : SampleSurfaceView? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_surface_view)
    }

    override fun onResume() {
        super.onResume()

        val surfaceView = findViewById<SurfaceView>(R.id.surfaceView)
        mainSurfaceView = SampleSurfaceView(surfaceView)
    }
}

SurfaceHolder用のクラスを作成し、SurfaceViewに描画する。
今回は、ランナーが右から左に通過するサンプルを作ってみました。

SampleSurfaceHolder.kt
import android.view.SurfaceHolder
import android.view.SurfaceView
import android.graphics.*

class SampleSurfaceHolder : SurfaceHolder.Callback, Runnable {
    private val _migrationLength : Int = 50
    private val _holder: SurfaceHolder
    private val _surface: SurfaceView

    private var _thread: Thread? = null
    private var _isCancel = false

    constructor(surface: SurfaceView) {
        _holder = surface.holder
        _holder.addCallback(this)
        _surface = surface
    }

    override fun surfaceChanged(holder: SurfaceHolder?, format: Int, width: Int, height: Int) {
    }

    override fun surfaceDestroyed(holder: SurfaceHolder?) {
        _isCancel = true
        _thread = null
    }

    override fun surfaceCreated(holder: SurfaceHolder?) {
        _thread = Thread(this)
        _thread?.start()
    }

    override fun run() {
        var cnt = 0
        val runner = Runner()

        while (!_isCancel) {
            val canvas = _holder.lockCanvas()

            val bitmap = runner.createBitmap()
            var x = - bitmap.width
            if (_surface.width < (x + cnt * _migrationLength )) {
                cnt = 0
            } else {
                x += cnt * _migrationLength
            }

            val paint = Paint()
            canvas.drawColor(0, PorterDuff.Mode.CLEAR)
            canvas.drawBitmap(bitmap, x.toFloat(), (_surface.height - bitmap.height).toFloat(), paint)

            _holder.unlockCanvasAndPost(canvas)
            Thread.sleep(150L)
            cnt++
        }
    }

    private class Runner {
        private val _magnification : Float = 10F
        private val _color = arrayOf(
                0xff000000, // 0
                0xff777777  // 1
        )

        private val _position: Array<IntArray> = arrayOf(intArrayOf(
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0,
                0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
                0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
                0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
                0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0,
                0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0,
                0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
                0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
                0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
                0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
                0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
                0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
                0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
                0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
                0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
                0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
                0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
                0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
                0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
                0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0
            ),
            intArrayOf(
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0,
                0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
                0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
                0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
                0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
                0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0,
                0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0,
                0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
                0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
                0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
                0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
                0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
                0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
                0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
                0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
                0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
                0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,
                0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0,
                0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0,
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
            )
        )
        private var _index = 0

        fun createBitmap(): Bitmap {
            val pixels = Array(16 * 22) { Color.BLACK }
            for (y in 0..(22 - 1)) {
                for (x in 0..(16 - 1)) {
                    pixels[x + y * 16] = _color[_position[_index % 2][x + y * 16]].toInt()
                }
            }
            _index = if (++_index >= _position.size) 0 else _index

            val bitmap = Bitmap.createBitmap(16, 22, Bitmap.Config.ARGB_8888)
            bitmap.setPixels(pixels.toIntArray(), 0, bitmap.width, 0, 0, bitmap.width, bitmap.height)
            val matrix = Matrix()
            matrix.setScale(_magnification, _magnification)
            return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix,true)
        }
    }
}
4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5