Fork me on GitHub

Saturday, April 19, 2014

Press-and-hold action on Android

Sometimes we need to receive repeated callback when a user pressing a button continuously. For example, when we make a number picker, press-and-hold on "+" button will constantly increase the number.

Android does not support this explicitly, but we can handle this behavior with postDelayed event. Here is a link to a code snippet doing this:


This works fine, but a little remaining problem is that this code should be encapsulated to be reused in other places. I wrote the following trait doing the encapsulation:

trait PressAndHoldable {
  def basis: android.view.View

  class PressAndHoldListener(interval: Int, onPressed: () => Unit) extends View.OnTouchListener with View.OnLongClickListener {
    var autoIncrementing: Boolean = false
    private val repeatUpdateHandler = new android.os.Handler()

    override def onTouch(v: View, event: MotionEvent): Boolean = {
      if (event.getAction == MotionEvent.ACTION_UP && autoIncrementing) {
        autoIncrementing = false
      }
      false
    }

    override def onLongClick(p1: View): Boolean = {
      autoIncrementing = true
      repeatUpdateHandler.post(new RptUpdater)
      false
    }

    class RptUpdater extends Runnable {
      override def run() {
        if (autoIncrementing) {
          onPressed()
          repeatUpdateHandler.postDelayed(this, interval)
        }
      }
    }
  }

  def onPressAndHold(interval: Int, onPressed: => Unit) {
    val listener = new PressAndHoldListener(interval, () => onPressed)
    basis.setOnTouchListener(listener)
    basis.setOnLongClickListener(listener)
  }
}

This trait is added on Scaloid 3.3 release. So you can just use onPressAndHold method for any android.view.View objects:
val num = STextView("0")
SButton("Increase").onPressAndHold(100, num.text = (num.text.toString.toInt + 1).toString)

No comments:

Post a Comment