Android:ButterKnifeでボタンのイベントを復習する
普段からAndroidアプリを開発していてもボタンの長押しイベントのハンドリングやタッチイベントの発生順序など、細かい部分はよく忘れがちで、実装する都度調べ直すことも多いかと思います。
今回は備忘録としてボタン操作時のイベントハンドリングを復習してみます。 ついでにせっかくなのでButterKnifeを使って確認してみました。
ButterKnifeの導入
今回はButterKnifeを使ってみます。AndroiderならButterKnifeはご存知かと思いますが、一言で言うと「ViewInjectionに特化した軽量ライブラリ」です。
ButterKnifeを使うことで面倒なfindViewById
を使わなくてもよくなり、記述量が減ることでコードの見た目もすっきりします。
さらにViewInjectionだけではなく@OnClick
@OnTouch
などのアノテーションでイベント発生時に実行するメソッドを指定することができるようですね。こいつぁ便利。
具体的な導入方法は各所で分かりやすい入門記事がいくつもあるので以下の記事などを参照してください。
イベント発生順を理解する
Androidアプリのボタンにリスナを設定する場合は主にOnClickListener
OnLongClickListener
OnTouchListener
の3種類を使うことになると思います。
以下のようなサンプルアプリでそれぞれの動作を確認してみます。
以下のコードで、それぞれのイベント発生時にイベント名が表示されます。
ここではタッチ、クリック、長押しの各イベントをハンドリングしています。
onTouch
タッチイベントはView.OnTouchListener
のonTouch(View v, MotionEvent event)
でハンドリングできます。ButterKnifeではメソッドに@onTouch
アノテーションを指定することで、タッチイベントが発生した時にそのメソッドが実行されます。各操作に応じて引数のMotionEventに入る値が変化します。
OnTouchListenerをセットしたコンポーネントをタッチした場合のイベント発生順は以下のようになります。
- ACTION_DOWN
- ACTION_MOVE(ACTION_DOWN状態で指を動かした場合)
- ACTION_POINTER_DOWN(ACTION_DOWN状態で他の指で任意の場所をタップした場合)
- ACTION_POINTER_UP(ACTION_POINTER_DOWN状態で新しくタップした指を離した場合)
- ACTION_UP(ACTION_DOWN状態から全ての指を離した場合)
なおonTouchでは戻り値でbooleanを返す必要があります。ここでfalseを返すと他のコンポーネントまでイベントが通知されますが、trueを返すとここでイベントが消費される扱いとなるため、このコンポーネント以降のコールバックが実行されなくなるので注意が必要です。
onTouchではMotionEvent.ACTION_CANCEL
もハンドリングすることができます。ACTION_CANCELをハンドリングしなければならないことはあまりないでしょうが、これが発生する場合を知っておくのもいいかと思います。
コンポーネントのタッチイベントがキャンセルされるケースはあまりないですが、一例を上げると、コンポーネントのタッチ中に画面遷移を行うなどでACTION_CANCELが通知されてくるようです。
サンプルアプリでは「TOUCH ME」ボタンに触れたままバックキーで戻るとToastが表示されるようにしています。
onClick
クリックイベントはView.OnClickListener
のonClick(View v)
でハンドリングできます(最早わざわざ言及するまでもないですね)。ButterKnifeではメソッドに@onClick
アノテーションを指定することで、クリックイベントが発生した時にそのメソッドが実行されます。なお@onClick
アノテーションには複数のボタンIDを指定できます。
onClickが実行されるのはタップした指が離された後です。つまりonTouch(MotionEvent == ACTION_UP)より後で実行されることになります。onTouchの戻り値でtrueを返しているとonClickが実行されないので注意が必要です。
onLongClick
長押しイベントはView.OnLongClickListener
のonLongClick(View v)
でハンドリングできます。ButterKnifeではメソッドに@onLongClick
アノテーションを指定することで、長押しイベントが発生した時にそのメソッドが実行されます。onLongClickは、コンポーネントがタップされて一定時間経過後に一度だけ実行されます。
onLongClickもonClick同様onTouchより後で実行されるため、このメソッドでイベントをハンドリングするためにはonTouchでtrueを返すようにしてやる必要があります。
まとめ
以上の結果をまとめると、ボタンタップ時のイベント発生順序は以下の通りです。onTouchでfalseを返した場合の動作となります。
- onTouch(MotionEvent == ACTION_DOWN)
- onTouch(MotionEvent == ACTION_MOVE)
- onLongClick(長押し時)
- onTouch(MotionEvent == ACTION_UP)
- onClick
サンプルアプリのソースを公開しておくので興味のある方は色々遊んでみてください。