読者です 読者をやめる 読者になる 読者になる

techium

このブログは何かに追われないと頑張れない人たちが週一更新をノルマに技術情報を発信するブログです。もし何か調査して欲しい内容がありましたら、@kobashinG or @muchiki0226 までいただけますと気が向いたら調査するかもしれません。

Android:ButterKnifeでボタンのイベントを復習する

Android ButterKnife Library

普段からAndroidアプリを開発していてもボタンの長押しイベントのハンドリングやタッチイベントの発生順序など、細かい部分はよく忘れがちで、実装する都度調べ直すことも多いかと思います。

今回は備忘録としてボタン操作時のイベントハンドリングを復習してみます。 ついでにせっかくなのでButterKnifeを使って確認してみました。

ButterKnifeの導入

今回はButterKnifeを使ってみます。AndroiderならButterKnifeはご存知かと思いますが、一言で言うと「ViewInjectionに特化した軽量ライブラリ」です。

ButterKnifeを使うことで面倒なfindViewByIdを使わなくてもよくなり、記述量が減ることでコードの見た目もすっきりします。

さらにViewInjectionだけではなく@OnClick @OnTouchなどのアノテーションでイベント発生時に実行するメソッドを指定することができるようですね。こいつぁ便利。

具体的な導入方法は各所で分かりやすい入門記事がいくつもあるので以下の記事などを参照してください。

イベント発生順を理解する

Androidアプリのボタンにリスナを設定する場合は主にOnClickListener OnLongClickListener OnTouchListenerの3種類を使うことになると思います。

以下のようなサンプルアプリでそれぞれの動作を確認してみます。 f:id:snishimura0926:20160403031939p:plain

以下のコードで、それぞれのイベント発生時にイベント名が表示されます。

AndroidButtonEventSample

ここではタッチ、クリック、長押しの各イベントをハンドリングしています。

onTouch

タッチイベントはView.OnTouchListeneronTouch(View v, MotionEvent event)でハンドリングできます。ButterKnifeではメソッドに@onTouchアノテーションを指定することで、タッチイベントが発生した時にそのメソッドが実行されます。各操作に応じて引数のMotionEventに入る値が変化します。

OnTouchListenerをセットしたコンポーネントをタッチした場合のイベント発生順は以下のようになります。

  1. ACTION_DOWN
  2. ACTION_MOVE(ACTION_DOWN状態で指を動かした場合)
  3. ACTION_POINTER_DOWN(ACTION_DOWN状態で他の指で任意の場所をタップした場合)
  4. ACTION_POINTER_UP(ACTION_POINTER_DOWN状態で新しくタップした指を離した場合)
  5. ACTION_UP(ACTION_DOWN状態から全ての指を離した場合)

なおonTouchでは戻り値でbooleanを返す必要があります。ここでfalseを返すと他のコンポーネントまでイベントが通知されますが、trueを返すとここでイベントが消費される扱いとなるため、このコンポーネント以降のコールバックが実行されなくなるので注意が必要です。

onTouchではMotionEvent.ACTION_CANCELもハンドリングすることができます。ACTION_CANCELをハンドリングしなければならないことはあまりないでしょうが、これが発生する場合を知っておくのもいいかと思います。

コンポーネントのタッチイベントがキャンセルされるケースはあまりないですが、一例を上げると、コンポーネントのタッチ中に画面遷移を行うなどでACTION_CANCELが通知されてくるようです。

サンプルアプリでは「TOUCH ME」ボタンに触れたままバックキーで戻るとToastが表示されるようにしています。

onClick

クリックイベントはView.OnClickListeneronClick(View v)でハンドリングできます(最早わざわざ言及するまでもないですね)。ButterKnifeではメソッドに@onClickアノテーションを指定することで、クリックイベントが発生した時にそのメソッドが実行されます。なお@onClickアノテーションには複数のボタンIDを指定できます。

onClickが実行されるのはタップした指が離された後です。つまりonTouch(MotionEvent == ACTION_UP)より後で実行されることになります。onTouchの戻り値でtrueを返しているとonClickが実行されないので注意が必要です。

onLongClick

長押しイベントはView.OnLongClickListeneronLongClick(View v)でハンドリングできます。ButterKnifeではメソッドに@onLongClickアノテーションを指定することで、長押しイベントが発生した時にそのメソッドが実行されます。onLongClickは、コンポーネントがタップされて一定時間経過後に一度だけ実行されます。

onLongClickもonClick同様onTouchより後で実行されるため、このメソッドでイベントをハンドリングするためにはonTouchでtrueを返すようにしてやる必要があります。

まとめ

以上の結果をまとめると、ボタンタップ時のイベント発生順序は以下の通りです。onTouchでfalseを返した場合の動作となります。

  1. onTouch(MotionEvent == ACTION_DOWN)
  2. onTouch(MotionEvent == ACTION_MOVE)
  3. onLongClick(長押し時)
  4. onTouch(MotionEvent == ACTION_UP)
  5. onClick

サンプルアプリのソースを公開しておくので興味のある方は色々遊んでみてください。

github.com