onDraw
method of our View
object. This method is implemented simply by simply overriding onDraw
and finally calling postInvalidateOnAnimation()
.drawable
will move along the x axis. override fun onDraw(canvas: Canvas) { super.onDraw(canvas) x += resources.getDimension(R.dimen.speed) drawable.setBounds(x, y, x + size, y + size) drawable.draw(canvas) postInvalidateOnAnimation() }
class SnowAnimation : View { ... private lateinit var snowflakes: Array<Snowflake> override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { snowflakes = Array(10, { Snowflake(right - left, bottom - top, context.getDrawable(R.drawable.snowflake), resources.getDimension(R.dimen.max_snowflake_size), resources.getDimension(R.dimen.max_snowflake_speed)) }) } override fun onDraw(canvas: Canvas) { super.onDraw(canvas) snowflakes.forEach { it.update() it.draw(canvas) } postInvalidateOnAnimation() } }
internal class Snowflake(private val containerWidth: Int, private val containerHeight: Int, private val drawable: Drawable, private val maxSize: Float, private val maxSpeed: Float) { private var size: Double = 0.0 private var speed: Double = 0.0 private var x: Double = 0.0 private var y: Double = 0.0 init { reset() } private fun reset() { size = Math.random() * maxSize / 2 + maxSize / 2 speed = Math.random() * maxSpeed / 2 + maxSpeed / 2 y = -size; x = Math.random() * containerWidth } fun update() { y += speed if (y > containerHeight) { reset() } } fun draw(canvas: Canvas?) { if (canvas == null) { return } drawable.setBounds(x.toInt(), y.toInt(), (x + size).toInt(), (y + size).toInt()) drawable.draw(canvas) } }
SurfaceView
. And since we are no longer tied to the main loop, we will have to keep our flow for calculations and rendering. SurfaceView
provides callbacks in which we can start and stop our stream. In the stream at the end of the calculations, we will draw our animation. class MySurfaceView : SurfaceView, SurfaceHolder.Callback { ... private lateinit var drawThread: DrawThread; init { holder.addCallback(this) } override fun surfaceCreated(holder: SurfaceHolder) { // surface drawThread = DrawThread(getHolder(), context, measuredWidth, measuredHeight) drawThread.start() } override fun surfaceDestroyed(holder: SurfaceHolder) { var retry = true // surface drawThread.cancel(); // , , . . while (retry) { try { drawThread.join() retry = false } catch (e: InterruptedException) { } } } } internal class DrawThread(private val surfaceHolder: SurfaceHolder, context: Context, width: Int, height: Int) : Thread() { private var snowflakes: Array<Snowflake> private var cancelled: Boolean = false init { snowflakes = Array(10, { Snowflake(width, height, context.getDrawable(R.drawable.snowflake), context.resources.getDimension(R.dimen.max_snowflake_size), context.resources.getDimension(R.dimen.max_snowflake_speed)) }) } override fun run() { while (!cancelled) { // canvas var canvas: Canvas? = surfaceHolder.lockCanvas() try { // onDraw View , , . canvas?.drawColor(Color.WHITE) snowflakes.forEach { it.update() it.draw(canvas) } } finally { if (canvas != null) { // canvas surfaceHolder.unlockCanvasAndPost(canvas) } } } } fun cancel() { cancelled = true } }
Source: https://habr.com/ru/post/348664/
All Articles