MenusThe Android mini-app frameworkDialogsTimer and animation

Timer and animation

The mini-app framework only calls onDraw() when the screen needs to be redrawn. As we saw before, you can request this using update. Since you can only call update from one of your methods, which are only called during a tap handler, this means that the screen will remain static until the user performs some action.

If you want the display to change over time, you need to use a timer. A timer is set by calling the context method after. It takes two arguments, the first indicates a number \(m\) of milliseconds, the second is a function object taking no parameters. The function object will be called automatically \(m\) milliseconds later.

Here is an example that uses a timer to let a ball drop down on the screen: (animation.kt):

//
// Animation with "after"
//

import org.otfried.cs109.Context
import org.otfried.cs109.MiniApp

import org.otfried.cs109.Canvas
import org.otfried.cs109.Color
import org.otfried.cs109.DrawStyle
import org.otfried.cs109.TextAlign

class Main(val ctx: Context) : MiniApp {
  var y: Double = 0.0
  var dead = false

  init {
    ctx.setTitle("Animation demo")
    ctx.onFling { x0, y0, dir, dist -> if (dir == 'u') y = 0.0; ctx.update() }
    ctx.after(20) { animate() }
  }

  fun animate() {
    y += 6.0
    ctx.update()
    if (y > ctx.height)
      dead = true
    else
      ctx.after(20) { animate() }
  }

  override fun onDraw(canvas: Canvas) {
    if (dead) {
      canvas.clear(Color(172, 0, 0)) // blood-red
    } else {    
      val x = canvas.width / 2.0
      canvas.clear(Color(255, 255, 192))
      canvas.setColor(Color.BLUE)
      canvas.drawCircle(x, y, 30.0)
    }
  }
}

You can fling upwards to move the ball back to the beginning. If you fail to do so before it reaches the bottom, the animation ends.

Note that we need to call ctx.after again inside the animate method to keep the animation running.

Some practical considerations:

MenusThe Android mini-app frameworkDialogsTimer and animation