banner
jzman

jzman

Coding、思考、自觉。
github

Androidイベントディスパッチプロセスの分析

PS: あまり焦らず、着実に自分を充実させることが最も重要です。

上篇文章では、Activity、ViewGroup、および View に関連するイベントメソッドの基本的な概要を説明しました。以下では、ケーススタディの形式で Android におけるイベント伝播をまとめます。

  1. デフォルトのイベント配信プロセス
  2. イベント配信
  3. イベント処理
  4. イベントインターセプト
  5. まとめ

デフォルトのイベント配信プロセス#

Android のイベント配信の正常なプロセス、つまりデフォルトの状態でイベントがどのように配信されるかを説明します。まず、カスタム ViewGroup とカスタム View を作成します。例えば、LinearLayout を継承してカスタム ViewGroup を MLinearLayout、TextView を継承してカスタム View を MTextView とし、それぞれのイベント配信に関連するメソッドをオーバーライドします。Activity も自分のイベントメソッドをオーバーライドし、ログを観察して正常なイベント配信プロセスを確認します。レイアウトは以下の図のようになります:

image

MTextView の onTouch イベントをトリガーすることで、各イベント配信メソッドがデフォルトで処理され、実行プロセスは以下の図のようになります:

image

明らかに、イベント配信の出発点は Activity の dispatchTouchEvent () メソッドであり、その後、一連のアクションイベントが ViewGroup に配信されます。具体的には、ViewGroup の dispatchTouchEvent () メソッドを呼び出します。ViewGroup の onInterceptTouchEvent () メソッドはデフォルトで false を返し、つまりデフォルトではイベントをインターセプトせず、子 View(ViewGroup も子 View である MRelativeLayout など)に向けてイベントを配信し続けます。そして、最も内側の子 View まで配信されます。

もちろん、イベントが子 View に配信されると、子 View の dispatchTouchEvent () メソッドが呼び出され、その内部で onTouchEvent () メソッドが呼び出されます。onTouchEvent () はデフォルトで false を返し、これはその View がイベントを消費しないことを示します。逆に true を返すと、そのイベントを消費します。以下は、上記の実行結果に基づいて描画されたデフォルトのイベント配信プロセスです。以下の図のようになります:

image

上記の検証を通じて、少なくとも各イベント関連メソッドの実行順序を理解できるでしょう。

イベント配信#

dispatchTouchEvent () メソッドはイベントの配信を担当し、現在のイベントが自身で消費されるか、子 View に配信されるかを決定します。true を返すと、イベントが消費されたことを示し、その後のイベント(ACTION_MOVE、ACTION_UP など)も引き続き実行されます。false を返すと、子 View にイベントが配信され続けます。もし子 View が ViewGroup であれば、最初に onInterceptTouchEvent () メソッドにイベントが配信され、イベントをインターセプトするかどうかが決まります。上記のケースに従い、MRelativeLayout の dispatchTouchEvent () メソッドが true を返すと、イベントが消費され、その後の一連のイベントを受け入れます。ログのスクリーンショットは以下の図のようになります:

image

明らかに、MRelativeLayout の dispatchTouchEvent () メソッドが true を返すと、イベントは下に伝播しません。ここでは、各イベントメソッドの実行をより明確に観察するために、具体的なイベント(ACTION_DOWN など)はログに出力されていません。したがって、dispatchTouchEvent () メソッドが true を返すと、イベントが消費されたことを示します。

イベントインターセプト#

onInterceptTouchEvent () メソッドはイベントのインターセプトを担当し、その返り値は現在のイベントをインターセプトするかどうかを決定します。返り値が true の場合、現在のイベントをインターセプトすることを示し、逆にイベントをインターセプトしない場合、デフォルトの実装では子 View の dispatchTouchEvent () メソッドを呼び出してイベントを配信し続けます。上記のケースに従い、MRelativeLayout の onInterceptTouchEvent () メソッドの返り値を true に設定すると、現在のイベントがインターセプトされ、イベントが下に伝播しなくなります。ログのスクリーンショットは以下の図のようになります:

image

イベントがインターセプトされた後は、イベント処理を行う必要があります。もちろん、イベント処理は onTouchEvent () メソッドが担当します。onTouchEvent () は処理することも、処理しないこともできます。onTouchEvent () が true を返すと、イベント処理が完了したことを意味し、false を返すと、イベントは親 View の onTouchEvent () メソッドによって処理されます。図示された状況では、MRelativeLayout がイベントをインターセプトしましたが、イベントを処理せず、最終的に Activity に処理を委ねます。

イベント処理#

onTouchEvent () メソッドはイベントの処理を担当し、その返り値はそのイベントを消費するかどうかを決定します。true を返すと、現在の View がイベントを消費することを示し、false を返すと、イベントは親 View の方向に伝播します。上記のケースに従い、MRelativeLayout の onTouchEvent () メソッドの返り値を true に設定すると、ログのスクリーンショットは以下の図のようになります:

image

上記のスクリーンショットでは、いくつかの ACTION_MOVE イベントが省略されています。ある View がイベントをインターセプトに成功した場合、ACTION_DOWN の後の一連のイベントはその View によって直接処理されます。

まとめ#

  1. イベント配信は親 View から子 View にイベントを配信します。配信の過程でインターセプトや処理が行われなければ、最も深い View に配信され、イベントは上に戻され、最終的に Activity によって処理されます。その後のイベントは受け付けられません。途中である View がイベントをインターセプトして処理を行った場合、インターセプトした View の onTouchEvent () メソッドによって処理されます。途中である View がイベントをインターセプトし、処理を行わない場合、イベントは子 View への配信を停止し、親 View の方向に親 View の onTouchEvent () メソッドによって処理されます。
  2. イベントがインターセプトに成功した後は、イベントを処理する必要があります。イベントの処理は主にインターセプトした View の onTouchEvent () メソッドまたはその親 View の onTouchEvent () によって行われます。処理するかどうかは、対応する onTouchEvent () メソッドの返り値によって決まります。
  3. イベントの処理はもちろん onTouchEvent () メソッドによって行われます。true を返すと、イベントはそこで処理され、逆にイベントが処理されていない場合は、上に戻され、処理されるまで続きます。

関連記事#

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。