Touch イベント配信の主役は ViewGroup と View の 2 人だけです。 Activity の Touch イベントは実際に内部 ViewGroup の Touch イベントを呼び出し、ViewGroup として直接処理できます。
View は ViewGroup 内にあり、ViewGroup は他の ViewGroup 内に存在することもできます。このとき、内部の ViewGroup は View として分析されます。
ViewGroup には、onInterceptTouchEvent、dispatchTouchEvent、onTouchEvent の 3 つの関連イベントがあります。 View に関連するイベントは、dispatchTouchEvent と onTouchEvent の 2 つだけです。
まず、ViewGroup の処理フローを分析します。まず、構造モデルの概念が必要です。ViewGroup と View はツリー構造を形成しており、その下に複数の ViewGroup ノードがあります。各ノードの下に ViewGroup ノードや View ノードなどがあります。図に示すように:
Touchイベント(例えばタッチイベント)がルートノード、つまりActiveのViewGroupに到達すると、配信処理はdispatchTouchEventメソッドを呼び出すことで実装されます。サブビュー (ViewGroup) 。簡単に言うと、ViewGroup はそれに含まれるサブ View を走査し、各 View のdispatchTouchEvent メソッドを呼び出します。サブ View が ViewGroup の場合、その内部 View のdispatchTouchEvent メソッドを呼び出し続けます。ビューグループ。上記例のメッセージ配信順序は、①-②-⑤-⑥-⑦-③-④となります。 dispatchTouchEvent メソッドはイベントの配信のみを行います。戻り値が true の場合、順次配信は中断されます。上記例では、⑤のdispatchTouchEventがtrueを返した場合、⑥-⑦-③-④はこのTouchイベントを受信しません。理解を深めるためにコードの簡単なバージョンを見てみましょう:
/** * ViewGroup * @param ev * @return */ public boolean dispatchTouchEvent(MotionEvent ev){ ....//其他处理,在此不管 View[] views=getChildView(); for(int i=0;i<views.length;i++){ //判断下Touch到屏幕上的点在该子View上面 if(...){ if(views[i].dispatchTouchEvent(ev)) return true; } } ...//其他处理,在此不管 } /** * View * @param ev * @return */ public boolean dispatchTouchEvent(MotionEvent ev){ ....//其他处理,在此不管 return false; }
ここで、ViewGroup のdispatchTouchEvent が実際には「配布」作業を実行しているのに対し、View のdispatchTouchEvent メソッドは配布作業を実行しないか、配布するオブジェクト自体がであることがわかります。 、タッチイベントを自分に渡すかどうかを決定し、処理のメソッドはonTouchEventイベントです。実際、サブViewのdispatchTouchEventメソッドで実際に実行されるコードは次のようになります
/** * View * @param ev * @return */ public boolean dispatchTouchEvent(MotionEvent ev){ ....//其他处理,在此不管 return onTouchEvent(event); }
通常の状況では、次のようにする必要があります。通常のビューでは繰り返さないでください。配布ロジックを実行しないため、dispatchTouchEvent メソッドを記述します。 Touch イベントが View に到達したときに行うべきことは、それを onTouchEvent イベントで処理するかどうかです。
では、ViewGroup の onTouchEvent イベントはいつ処理されるのでしょうか? ViewGroup のすべてのサブビューが false を返すと、onTouchEvent イベントが実行されます。 ViewGroup は View を継承するため、実際には View のdispatchTouchEvent メソッドを呼び出して onTouchEvent イベントを実行します。
現在の状況から、すべての onTouchEvent に false を返す限り、すべてのサブコントロールがこの Touch イベントに応答することを保証できるように見えます。ただし、ここでの Touch イベントは Action_Down イベント、つまりタッチを押すイベントに限定されており、Aciton_UP と Action_MOVE は実行されないことに注意する必要があります。実際、完全な Touch イベントは、Down、Up、およびいくつかの Move で構成されている必要があります。ダウン モードは、dispatchTouchEvent を通じて配布されます。配布の目的は、完全な Touch リクエストを処理する必要があるビューを見つけることです。 View または ViewGroup の onTouchEvent イベントが true を返した場合、実際にこのリクエストを処理したいのは View であり、後続の Aciton_UP および Action_MOVE は View によって処理されることを意味します。すべての子ビューの onTouchEvent が false を返すと、この Touch リクエストはルート ViewGroup、つまりアクティビティ自体によって処理されます。
ViewGroup の改良されたdispatchTouchEvent メソッドを見てください
View mTarget=null;//保存捕获Touch事件处理的View public boolean dispatchTouchEvent(MotionEvent ev) { //....其他处理,在此不管 if(ev.getAction()==KeyEvent.ACTION_DOWN){ //每次Down事件,都置为Null if(!onInterceptTouchEvent()){ mTarget=null; View[] views=getChildView(); for(int i=0;i<views.length;i++){ if(views[i].dispatchTouchEvent(ev)) mTarget=views[i]; return true; } } } //当子View没有捕获down事件时,ViewGroup自身处理。这里处理的Touch事件包含Down、Up和Move if(mTarget==null){ return super.dispatchTouchEvent(ev); } //...其他处理,在此不管 if(onInterceptTouchEvent()){ //...其他处理,在此不管 } //这一步在Action_Down中是不会执行到的,只有Move和UP才会执行到。 return mTarget.dispatchTouchEvent(ev); }
ViewGroup には onInterceptTouchEvent もあります。名前から、これがインターセプト イベントであることがわかります。このインターセプト イベントは 2 つの状況で説明する必要があります:
1. ViewGroup の onInterceptTouchEvent で true を返し、Touch イベントに対して Action が Down である場合、これは ViewGroup のすべての配信操作がインターセプトされることを意味します。この場合、mTarget には Down イベントで値が割り当てられるため、mTarget は常に null になります。 mTarge が null なので、ViewGroup の onTouchEvent イベントが実行されます。この場合、ViewGroup を直接 View として扱うことができます。
2. ViewGroup の onInterceptTouchEvent にいる場合、Action が Down であるすべての Touch イベントは False を返し、そのサブ View がすべて返されれば、Down イベントは正常に配信されます。 false の場合、mTarget は空のままで、効果はありません。サブビューが true を返し、mTarget に値が割り当てられている場合、ViewGroup に Action_Move と Aciton_UP を配布すると、Action_Delete の MotionEvent が mTarget に配布され、同時に mTarget の値がクリアされます。 next Action_Move (前の操作が UP でない場合) は ViewGroup の onTouchEvent によって処理されます。
シナリオ 1 はより頻繁に使用されますが、シナリオ 2 はまだ見つかりません。
最初から最後まで要約すると:
1. Touch イベント配信の主役は ViewGroup と View の 2 人だけです。 ViewGroup には、onInterceptTouchEvent、dispatchTouchEvent、および onTouchEvent という 3 つの関連イベントが含まれています。ビューには、dispatchTouchEvent と onTouchEvent という 2 つの関連イベントが含まれています。このうち、ViewGroupはViewを継承しています。
2. ViewGroup と View はツリー構造を形成し、ルート ノードはアクティビティ内に含まれる ViwGroup です。
3. タッチ イベントは、Action_Down、Action_Move、および Aciton_UP で構成されます。完全なタッチ イベントには、Down と Up が 1 つだけあり、Move は 0 になる可能性があります。
4. Activty が Touch イベントを受信すると、サブビューを走査して Down イベントを配信します。 ViewGroup のトラバーサルは再帰的であるとみなすことができます。配布の目的は、この完全なタッチ イベントを実際に処理するビューを見つけることです。このビューは、onTouchEvent の結果で true を返します。
5. サブビューが true を返すと、Down イベントの配信が停止され、サブビューが ViewGroup に記録されます。後続の Move および Up イベントは、サブビューによって直接処理されます。サブ View は ViewGroup に保存されるため、多層 ViewGroup ノード構造では、上位レベルの ViewGroup は、実際にイベントを処理する View が配置される ViewGroup オブジェクトを保存します。たとえば、ViewGroup0-ViewGroup1 の構造に保存されます。 -TextView、TextView は true を返し、これは ViewGroup1 に保存され、ViewGroup1 も true を返し、ViewGroup0 に保存されます。 Move および UP イベントが発生すると、それらはまず ViewGroup0 から ViewGroup1 に渡され、次に ViewGroup1 から TextView に渡されます。
6. ViewGroup 内のすべてのサブビューが Down イベントをキャプチャしない場合、ViewGroup 自体の onTouch イベントがトリガーされます。トリガーする方法は、親クラス View のdispatchTouchEvent メソッドである super.dispatchTouchEvent 関数を呼び出すことです。すべてのサブビューが処理されない場合、Activity の onTouchEvent メソッドがトリガーされます。
7.onInterceptTouchEvent には 2 つの機能があります: 1. Down イベントの配信をインターセプトします。 2. ターゲット ビューへの Up および Move イベントの配信を停止し、ターゲット ビューが配置されている ViewGroup が Up および Move イベントをキャプチャできるようにします。
補足:
「タッチ イベントは、Action_Down、Action_Move、および Aciton_UP で構成されます。完全なタッチ イベントでは、Down と Up は 1 つだけあり、Move は 0 になる可能性がいくつかあります。」とここで追加します。 UPイベントは実際には0かもしれません。
以上がこの記事の全内容です。Touch イベント配信の仕組みを理解するのに役立つことを願っています。
30 分で理解する Android Touch イベント配信メカニズムに関連するその他の記事については、PHP 中国語 Web サイトに注目してください。