パート2.複雑なアニメーション
パート3.「低レベル」アニメーション
パート4.遷移アニメーション
パート5.アニメーションを操作するためのライブラリ
前のパートで説明したすべての方法は便利で便利ですが、多数のオブジェクトをアニメーション化する必要がある場合、それらは適切ではない可能性があります。 このパートでは、非常に多くのオブジェクトを操作し、プログラム的に複雑なアニメーションを作成する方法を見ていきます。
パート3.「低レベル」アニメーション
1.キャンバスビューでの描画
最初に
onDraw
方法は、
View
オブジェクトの
onDraw
メソッドで描画することです。 このメソッドは、
onDraw
をオーバーライドし、最後に
postInvalidateOnAnimation()
を呼び出すだけで実装されます。
この例では、
drawable
はx軸に沿って移動します。
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) } }
アプリケーション:
- アニメーションをプログラムで簡単に描画できる場合
利点:
- 絶対にパラメーターに依存してアニメーションを作成できます
- Viewオブジェクトのオーバーヘッドなし
短所:
- アニメーションとレンダリングの計算はUIスレッドで行われます
2. Canvas SurfaceViewでの描画
次のアニメーションステップの計算にかなりの時間がかかる場合はどうなりますか? それでも最初の方法を使用して、計算を別のストリームに転送できます。 ただし、これでもアニメーションが100%滑らかになることはありません。 UIスレッドには、アニメーション以外のものを読み込むことができます。
Androidでは、
SurfaceView
コンポーネントを使用して、レンダリングのメインループを取り除くことができます。 また、メインサイクルに縛られなくなったため、計算とレンダリングのフローを維持する必要があります。
SurfaceView
は、ストリームを開始および停止できるコールバックを提供します。 ストリームでは、計算の最後にアニメーションを描画します。
同じスノーフレークアニメーションの実装は次のようになります。
コードを見せてください!
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 } }
アプリケーション:
- アニメーションをプログラムで簡単に描画できる場合
- ゲーム
利点:
- 絶対にパラメーターに依存してアニメーションを作成できます
- Viewオブジェクトのオーバーヘッドなし
短所:
- 実装の複雑さ
3. OpenGL
キャンバスと同様に、OpenGL APIを使用して描画できます。 写真の立方体よりも複雑なものを考えた場合、たとえばlibgdxのように、何らかのエンジンの方向を見る必要があります。 残念ながら、基本的な例でもここではかなりのスペースを占有するため、この短いプレビューのみに限定します。
アプリケーション:
- 複雑な効果
- 3D
- ゲーム
利点:
- 高性能およびメモリ管理、シェーダー
短所:
- 実装の複雑さ
ここですべての例を見て勉強できます 。