Android:30分Touchイベント配信メカニズムがわかります
転載先:http://www.cnblogs.com/linjzong/p/4191891.html
Touchイベント配信には、ViewGroupとViewの2人の主役しかいません.ActivityのTouchイベントは実際には内部のViewGroupを呼び出すTouchイベントであり,直接ViewGroupとして扱うことができる.
ビューはビューグループ内にあり、ビューグループは他のビューグループ内にも存在するが、この場合は内部のビューグループをビューとして分析する.
ViewGroupの関連イベントは、onInterceptTouchEvent、dispatchTouchEvent、onTouchEventの3つです.Viewの関連イベントは2つしかありません:dispatchTouchEvent、onTouchEvent.
まずView Groupの処理フローを分析する:まず構造モデルの概念が必要である:View GroupとViewは木の構造を構成し、最上位層はActivityのView Groupであり、下にはいくつかのView Groupノードがあり、各ノードの下にはいくつかのView GroupノードまたはViewノードがあり、順次類推される.図:
Touchイベント(タッチイベントの例)がルートノード、すなわちActivityのViewGroupに到達すると、順次ダウンし、ダウンするプロセスは、サブView(ViewGroup)のdispatchTouchEventメソッドを呼び出して実現される.簡単に言えば、View Groupは、含まれるサブViewを巡回し、各ViewのdispatchTouchEventメソッドを呼び出し、サブViewがView Groupの場合、ViwGroupのdispatchTouchEventメソッドを呼び出すことによって、内部のViewのdispatchTouchEventメソッドを呼び出し続ける.上記の例のメッセージの送信順序は、①-②-⑤-⑥-⑦-③-④である.dispatchTouchEventメソッドは、booleanタイプの戻り値を持つイベントの配布のみを担当し、戻り値がtrueの場合、シーケンスダウンが中断します.上記の例では、⑤のdispatchTouchEventが結果trueを返すと、⑥-⑦-③-④はいずれも今回のTouchイベントを受信できなくなる.簡単なバージョンのコードを理解してください.
ここで、ViewGroupのdispatchTouchEventは本当に「配布」の仕事を実行しているのに対し、ViewのdispatchTouchEventメソッドは、配布の仕事を実行していない、あるいはその配布の対象は自分であり、touchイベントを自分で処理するかどうかを決定し、処理する方法はonTouchEventイベントであることがわかります.実際にサブViewのdispatchTouchEventメソッドが実際に実行するコードはこうです
一般的には、配布ロジックが実行されないため、一般的なView内でdispatchTouchEventメソッドを書き換えるべきではありません.TouchイベントがViewに到達したとき、onTouchEventイベントで処理するかどうかです.
では、ViewGroupのonTouchEventイベントはいつ処理されたのでしょうか.ビューグループのすべてのサブビューがfalseに戻ると、onTouchEventイベントが実行されます.ViewGroupはViewに継承されるため、実際にはViewのdispatchTouchEventメソッドを呼び出すことによってonTouchEventイベントを実行します.
現在の状況では、すべてのonTouchEventをfalseに返すだけで、すべてのサブコントロールが今回のTouchイベントに応答することを保証できるようです.しかし、ここで説明しなければならないのは、ここのTouchイベントは、Activion_に限られていることです.Downイベント、すなわちタッチダウンイベント、そしてAciton_UPとAction_MOVEは実行されません.実際、完全なTouchイベントは、1つのDown、1つのUp、およびいくつかのMoveから構成されるべきである.Down方式はdispatchTouchEventによって配布され,配布の目的は完全なTouch要求を処理する必要があるViewを見つけることである.あるViewまたはView GroupのonTouchEventイベントがtrueを返すと、本当に今回のリクエストを処理するViewであり、その後のAciton_UPとAction_MOVEはそれによって処理されます.すべてのサブViewのonTouchEventがfalseに戻ると、今回のTouchリクエストはルートViewGroup、すなわちActivity自身が処理します.
改良されたViewGroupのdispatchTouchEvent法を見てみましょう
View GroupにはonInterceptTouchEventがあり、名前を見るとブロックイベントであることがわかります.このブロックイベントは2つの状況に分けて説明する必要があります.
1.あるView GroupのonInterceptTouchEventで、DownのActionのTouchイベントをtrueに戻すと、そのView Groupのすべてのダウンセット操作をブロックすることを意味します.この場合、mTargetはDownイベントで付与されているため、nullになります.mTargetがnullであるため、ViewGroupのonTouchEventイベントが実行される.この場合、このビューグループを直接ビューとして扱うことができます.
2.あるView GroupのonInterceptTouchEventで、ActionがDownのTouchイベントをfalseに戻し、その他はTrueに戻した場合、Downイベントは正常に配布され、サブViewがfalseに戻った場合、mTargetは空であり、影響はありません.ある子Viewがtrueを返すと、mTargetが付与され、Action_MoveとAciton_UPがこのViewGroupに配布されると、mTargetにAction_が配布されます.DeleteのMotionEventは、mTargetの値をクリアし、次のAction_Move(前の操作がUPでない場合)は、ViewGroupのonTouchEventによって処理されます.
ケースは1つで使用することが多く、2人で使用シーンが見つからない場合があります.
最初から最後までまとめます.
1.Touchイベント配信には、ViewGroupとViewの2つの主役しかいません.ViewGroupには、onInterceptTouchEvent、dispatchTouchEvent、onTouchEventの3つの関連イベントが含まれています.Viewには、dispatchTouchEvent、onTouchEventの2つの関連イベントが含まれています.このうちView GroupはViewに継承されます.
2.ViewGroupとViewは、Activityの内部に含まれるViwGroupのルートノードであるツリー構造を構成します.
3.タッチイベントはAction_Down、Action_Move、Aciton_UPは,1回の完全なタッチイベントのうち,DownとUpはいずれも1つのみであり,Moveはいくつかあり,0個であってもよい.
4.ActivityがTouchイベントを受信すると、Downイベントの配信はサブViewを巡回する.ViewGroupの遍歴は再帰的と見なすことができる.配布の目的は、今回の完全なタッチイベントを本当に処理するViewを見つけることです.このViewはonTouchuEventの結果でtrueを返します.
5.サブViewがtrueを返すと、Downイベントの配布が中止され、そのサブViewがView Groupに記録されます.次のMoveおよびUpイベントは、このサブViewによって直接処理される.サブViewがViewGroupに保存されているため、多層ViewGroupのノード構造の場合、上位のViewGroupが実際にイベントを処理するViewが存在するViewGroupオブジェクトが保存されます.たとえば、ViewGroup 0-ViewGroup 1-TextViewの構造では、TextViewがtrueを返し、ViewGroup 1に保存され、ViewGroup 1もtrueを返し、ViewGroup 0に保存されます.MoveおよびUPイベントが来ると、まずView Group 0からView Group 1に、さらにView Group 1からTextViewに渡されます.
6.Viewグループ内のすべてのサブViewがDownイベントをキャプチャしない場合、Viewグループ自体のonTouchイベントがトリガーされます.トリガはsuperを呼び出す.dispatchTouchEvent関数、すなわち親ViewのdispatchTouchEventメソッド.すべてのサブViewが処理されない場合、ActivityのonTouchEventメソッドがトリガーされます.
7.onInterceptTouchEventには2つの役割があります:1.Downイベントの配布をブロックします.2.UpおよびMoveイベントのターゲットViewへの転送を中止し、ターゲットViewが存在するViewGroupがUpおよびMoveイベントをキャプチャするようにする.
また、上記のコードは本物のソースコードではなく、イベント配信処理におけるソースコードのコア処理の流れを要約しているだけで、本物のソースコードの皆さんは自分で見ることができ、より豊富な内容が含まれています.
補足:
「タッチイベントはAction_Down、Action_Move、Aciton_UPで構成されており、1回の完全なタッチイベントのうち、DownとUpはいずれも1つのみであり、Moveはいくつかあり、0個であってもよい」.ここで補足すると実はUPイベントは0個かもしれません.
最近、ジェスチャーをして移動画像を拡大縮小しているDemoについて、もっと理解しました.onInterceptTouchEventイベントの場合、その応用シーンはscroll効果のある多くのView Groupに現れている.もう1つのViewPagerでは、各ItemがImageViewであることを想定します.これらのImageViewに対してMatrix操作を行う必要があります.これはTouchイベントをキャプチャすることは避けられませんが、ViewPagerのページをめくる効果に影響を与えないようにする必要があります.これは、ViewPagerがMoveイベントをキャプチャできることを保証する必要があります.そこで、ViewPagerのonInterceptTouchEventはMoveイベントをフィルタします.適切な条件のMoveイベント(いくつかのイベントを継続したり、いくつかの距離を移動したりします.ここではソースコードを読んでいませんが推測しています)がトリガーされると、ブロックされ、サブViewにAction_を返します.Cancelイベント.このとき子ViewにはUpイベントはなく,Upで処理する必要があるものはCancelで処理することが多い.
Touchイベント配信には、ViewGroupとViewの2人の主役しかいません.ActivityのTouchイベントは実際には内部のViewGroupを呼び出すTouchイベントであり,直接ViewGroupとして扱うことができる.
ビューはビューグループ内にあり、ビューグループは他のビューグループ内にも存在するが、この場合は内部のビューグループをビューとして分析する.
ViewGroupの関連イベントは、onInterceptTouchEvent、dispatchTouchEvent、onTouchEventの3つです.Viewの関連イベントは2つしかありません:dispatchTouchEvent、onTouchEvent.
まずView Groupの処理フローを分析する:まず構造モデルの概念が必要である:View GroupとViewは木の構造を構成し、最上位層はActivityのView Groupであり、下にはいくつかのView Groupノードがあり、各ノードの下にはいくつかのView GroupノードまたはViewノードがあり、順次類推される.図:
Touchイベント(タッチイベントの例)がルートノード、すなわちActivityのViewGroupに到達すると、順次ダウンし、ダウンするプロセスは、サブView(ViewGroup)のdispatchTouchEventメソッドを呼び出して実現される.簡単に言えば、View Groupは、含まれるサブViewを巡回し、各ViewのdispatchTouchEventメソッドを呼び出し、サブViewがView Groupの場合、ViwGroupのdispatchTouchEventメソッドを呼び出すことによって、内部のViewのdispatchTouchEventメソッドを呼び出し続ける.上記の例のメッセージの送信順序は、①-②-⑤-⑥-⑦-③-④である.dispatchTouchEventメソッドは、booleanタイプの戻り値を持つイベントの配布のみを担当し、戻り値がtrueの場合、シーケンスダウンが中断します.上記の例では、⑤のdispatchTouchEventが結果trueを返すと、⑥-⑦-③-④はいずれも今回のTouchイベントを受信できなくなる.簡単なバージョンのコードを理解してください.
/**
* ViewGroup
* @param ev
* @return
*/
public boolean dispatchTouchEvent(MotionEvent ev){
....// ,
View[] views=getChildView();
for(int i=0;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メソッドは、配布の仕事を実行していない、あるいはその配布の対象は自分であり、touchイベントを自分で処理するかどうかを決定し、処理する方法はonTouchEventイベントであることがわかります.実際にサブViewのdispatchTouchEventメソッドが実際に実行するコードはこうです
/**
* View
* @param ev
* @return
*/
public boolean dispatchTouchEvent(MotionEvent ev){
....// ,
return onTouchEvent(event);
}
一般的には、配布ロジックが実行されないため、一般的なView内でdispatchTouchEventメソッドを書き換えるべきではありません.TouchイベントがViewに到達したとき、onTouchEventイベントで処理するかどうかです.
では、ViewGroupのonTouchEventイベントはいつ処理されたのでしょうか.ビューグループのすべてのサブビューがfalseに戻ると、onTouchEventイベントが実行されます.ViewGroupはViewに継承されるため、実際にはViewのdispatchTouchEventメソッドを呼び出すことによってonTouchEventイベントを実行します.
現在の状況では、すべてのonTouchEventをfalseに返すだけで、すべてのサブコントロールが今回のTouchイベントに応答することを保証できるようです.しかし、ここで説明しなければならないのは、ここのTouchイベントは、Activion_に限られていることです.Downイベント、すなわちタッチダウンイベント、そしてAciton_UPとAction_MOVEは実行されません.実際、完全なTouchイベントは、1つのDown、1つのUp、およびいくつかのMoveから構成されるべきである.Down方式はdispatchTouchEventによって配布され,配布の目的は完全なTouch要求を処理する必要があるViewを見つけることである.あるViewまたはView GroupのonTouchEventイベントがtrueを返すと、本当に今回のリクエストを処理するViewであり、その後のAciton_UPとAction_MOVEはそれによって処理されます.すべてのサブViewのonTouchEventがfalseに戻ると、今回のTouchリクエストはルートViewGroup、すなわちActivity自身が処理します.
改良された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){
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);
}
View GroupにはonInterceptTouchEventがあり、名前を見るとブロックイベントであることがわかります.このブロックイベントは2つの状況に分けて説明する必要があります.
1.あるView GroupのonInterceptTouchEventで、DownのActionのTouchイベントをtrueに戻すと、そのView Groupのすべてのダウンセット操作をブロックすることを意味します.この場合、mTargetはDownイベントで付与されているため、nullになります.mTargetがnullであるため、ViewGroupのonTouchEventイベントが実行される.この場合、このビューグループを直接ビューとして扱うことができます.
2.あるView GroupのonInterceptTouchEventで、ActionがDownのTouchイベントをfalseに戻し、その他はTrueに戻した場合、Downイベントは正常に配布され、サブViewがfalseに戻った場合、mTargetは空であり、影響はありません.ある子Viewがtrueを返すと、mTargetが付与され、Action_MoveとAciton_UPがこのViewGroupに配布されると、mTargetにAction_が配布されます.DeleteのMotionEventは、mTargetの値をクリアし、次のAction_Move(前の操作がUPでない場合)は、ViewGroupのonTouchEventによって処理されます.
ケースは1つで使用することが多く、2人で使用シーンが見つからない場合があります.
最初から最後までまとめます.
1.Touchイベント配信には、ViewGroupとViewの2つの主役しかいません.ViewGroupには、onInterceptTouchEvent、dispatchTouchEvent、onTouchEventの3つの関連イベントが含まれています.Viewには、dispatchTouchEvent、onTouchEventの2つの関連イベントが含まれています.このうちView GroupはViewに継承されます.
2.ViewGroupとViewは、Activityの内部に含まれるViwGroupのルートノードであるツリー構造を構成します.
3.タッチイベントはAction_Down、Action_Move、Aciton_UPは,1回の完全なタッチイベントのうち,DownとUpはいずれも1つのみであり,Moveはいくつかあり,0個であってもよい.
4.ActivityがTouchイベントを受信すると、Downイベントの配信はサブViewを巡回する.ViewGroupの遍歴は再帰的と見なすことができる.配布の目的は、今回の完全なタッチイベントを本当に処理するViewを見つけることです.このViewはonTouchuEventの結果でtrueを返します.
5.サブViewがtrueを返すと、Downイベントの配布が中止され、そのサブViewがView Groupに記録されます.次のMoveおよびUpイベントは、このサブViewによって直接処理される.サブViewがViewGroupに保存されているため、多層ViewGroupのノード構造の場合、上位のViewGroupが実際にイベントを処理するViewが存在するViewGroupオブジェクトが保存されます.たとえば、ViewGroup 0-ViewGroup 1-TextViewの構造では、TextViewがtrueを返し、ViewGroup 1に保存され、ViewGroup 1もtrueを返し、ViewGroup 0に保存されます.MoveおよびUPイベントが来ると、まずView Group 0からView Group 1に、さらにView Group 1からTextViewに渡されます.
6.Viewグループ内のすべてのサブViewがDownイベントをキャプチャしない場合、Viewグループ自体のonTouchイベントがトリガーされます.トリガはsuperを呼び出す.dispatchTouchEvent関数、すなわち親ViewのdispatchTouchEventメソッド.すべてのサブViewが処理されない場合、ActivityのonTouchEventメソッドがトリガーされます.
7.onInterceptTouchEventには2つの役割があります:1.Downイベントの配布をブロックします.2.UpおよびMoveイベントのターゲットViewへの転送を中止し、ターゲットViewが存在するViewGroupがUpおよびMoveイベントをキャプチャするようにする.
また、上記のコードは本物のソースコードではなく、イベント配信処理におけるソースコードのコア処理の流れを要約しているだけで、本物のソースコードの皆さんは自分で見ることができ、より豊富な内容が含まれています.
補足:
「タッチイベントはAction_Down、Action_Move、Aciton_UPで構成されており、1回の完全なタッチイベントのうち、DownとUpはいずれも1つのみであり、Moveはいくつかあり、0個であってもよい」.ここで補足すると実はUPイベントは0個かもしれません.
最近、ジェスチャーをして移動画像を拡大縮小しているDemoについて、もっと理解しました.onInterceptTouchEventイベントの場合、その応用シーンはscroll効果のある多くのView Groupに現れている.もう1つのViewPagerでは、各ItemがImageViewであることを想定します.これらのImageViewに対してMatrix操作を行う必要があります.これはTouchイベントをキャプチャすることは避けられませんが、ViewPagerのページをめくる効果に影響を与えないようにする必要があります.これは、ViewPagerがMoveイベントをキャプチャできることを保証する必要があります.そこで、ViewPagerのonInterceptTouchEventはMoveイベントをフィルタします.適切な条件のMoveイベント(いくつかのイベントを継続したり、いくつかの距離を移動したりします.ここではソースコードを読んでいませんが推測しています)がトリガーされると、ブロックされ、サブViewにAction_を返します.Cancelイベント.このとき子ViewにはUpイベントはなく,Upで処理する必要があるものはCancelで処理することが多い.