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)
}
}
}