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
     * @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で処理することが多い.