267

AndroidonInterceptTouchEventとの違いは何ですか?dispatchTouchEvent

android開発者ガイドによると、両方の方法を使用してタッチイベント(MotionEvent)をインターセプトできますが、違いは何ですか?

ビューの階層内でどのようonInterceptTouchEventに相互作用しdispatchTouchEvent、相互作用しますか( )?onTouchEventViewGroup

4

14 に答える 14

292

これをわかりやすく説明するのに最適な場所は、ソース コードです。ドキュメントは、これを説明することについてひどく不十分です。

dispatchTouchEvent は、Activity、View、および ViewGroup で実際に定義されます。タッチ イベントのルーティング方法を決定するコントローラーと考えてください。

たとえば、最も単純なケースはView.dispatchTouchEventの場合で、タッチ イベントをOnTouchListener.onTouch (定義されている場合) または拡張メソッドonTouchEventにルーティングします。

ViewGroup.dispatchTouchEventの場合、事態はさらに複雑になります。その子ビューのどれがイベントを取得する必要があるかを把握する必要があります (child.dispatchTouchEvent を呼び出して)。これは基本的に、どの子ビューの境界矩形にタッチ ポイント座標が含まれているかを調べるヒット テスト アルゴリズムです。

ただし、イベントを適切な子ビューにディスパッチする前に、親はイベントをすべてスパイおよび/またはインターセプトできます。これがonInterceptTouchEventの目的です。そのため、ヒット テストを実行する前にこのメソッドを最初に呼び出し、(onInterceptTouchEvent から true を返すことによって) イベントがハイジャックされた場合は、子ビューにACTION_CANCELを送信して、(前のタッチ イベントからの) タッチ イベントの処理を破棄できるようにします。親レベルのすべてのタッチ イベントは、 onTouchListener.onTouch (定義されている場合) またはonTouchEvent () にディスパッチされます。その場合も、onInterceptTouchEvent が再度呼び出されることはありません。

[Activity|ViewGroup|View].dispatchTouchEvent をオーバーライドしたいですか? カスタムルーティングを行っていない限り、おそらくそうすべきではありません。

主な拡張メソッドは、親レベルでタッチ イベントをスパイおよび/またはインターセプトする場合は ViewGroup.onInterceptTouchEvent であり、メイン イベント処理用の View.onTouchListener/View.onTouchEvent です。

全体として、非常に複雑なデザインですが、Android API はシンプルさよりも柔軟性に傾いています。

于 2013-02-06T04:35:09.000 に答える
259

これは Google での最初の結果だからです。YouTubeで Dave Smith による素晴らしいトークを共有したいと思います: Mastering the Android Touch Systemとスライドはこちらから入手できます。Android Touch System について深く理解することができました。

アクティビティがタッチを処理する方法:

  • Activity.dispatchTouchEvent()
    • 常に最初に呼び出される
    • Window にアタッチされたルート ビューにイベントを送信します。
    • onTouchEvent()
      • イベントを消費するビューがない場合に呼び出されます
      • 常に最後に呼び出される

ビューがタッチを処理する方法:

  • View.dispatchTouchEvent()
    • 存在する場合は、最初にリスナーにイベントを送信します
      • View.OnTouchListener.onTouch()
    • 消費されない場合は、タッチ自体を処理します
      • View.onTouchEvent()

ViewGroupがタッチを処理する方法:

  • ViewGroup.dispatchTouchEvent()
    • onInterceptTouchEvent()
      • それが子に取って代わるべきかどうかを確認してください
      • アクティブ ACTION_CANCEL な子に渡します
      • 一度 true を返すと、ViewGroup以降のすべてのイベントが消費されます
    • 各子ビュー (追加された逆順)
      • タッチが関連する場合 (内部ビュー)、 child.dispatchTouchEvent()
      • 前のビューで処理されない場合は、次のビューにディスパッチします
    • イベントを処理する子がいない場合、リスナーにチャンスがあります
      • OnTouchListener.onTouch()
    • リスナーがない場合、または処理されない場合
      • onTouchEvent()
  • 傍受されたイベントが子ステップを飛び越える

彼は、 github.com/devunwired / でカスタム タッチのサンプル コードも提供しています。

回答: 基本的に、は進行中のジェスチャに関心があるかどうかを判断するために、すべてのレイヤーdispatchTouchEvent()で呼び出されます。には、子を呼び出す前に、メソッドでタッチ イベントを盗む機能があります。-method が true を返す場合にのみ、ディスパッチを停止します。違いは、ディスパッチであり、インターセプトする必要があるか(子にディスパッチしない)、インターセプトしないか(子にディスパッチする) を示します。ViewViewViewGroupViewGroupdispatchTouchEvent()dispatchTouchEvent()ViewGroupViewGroup onInterceptTouchEvent()dispatchTouchEvent()MotionEventsonInterceptTouchEventMotionEvent

多かれ少なかれこれを行うViewGroupのコードを想像できます(非常に単純化されています)。

public boolean dispatchTouchEvent(MotionEvent ev) {
    if(!onInterceptTouchEvent()){
        for(View child : children){
            if(child.dispatchTouchEvent(ev))
                return true;
        }
    }
    return super.dispatchTouchEvent(ev);
}
于 2014-03-18T20:53:52.930 に答える
88

補足回答

以下は、他の回答に対する視覚的な補足です。私の完全な答えはここにあります。

ここに画像の説明を入力

ここに画像の説明を入力

dispatchTouchEvent()メソッドは、 (ViewGroupを使用して)onInterceptTouchEvent()タッチ イベントをすぐに処理するか、その子のメソッドへのonTouchEvent()通知を続行するかを選択するために使用します。dispatchTouchEvent()

于 2017-10-21T10:39:40.860 に答える
9

このウェブページhttp://doandroids.com/blogs/tag/codeexample/で非常に直感的な説明に出くわしました。そこから取られた:

  • boolean onTouchEvent(MotionEvent ev) - このビューをターゲットとするタッチ イベントが検出されるたびに呼び出されます
  • boolean onInterceptTouchEvent(MotionEvent ev) - この ViewGroup またはその子をターゲットとしてタッチ イベントが検出されるたびに呼び出されます。この関数が true を返す場合、MotionEvent は傍受されます。つまり、子には渡されず、このビューの onTouchEvent に渡されます。
于 2012-07-10T23:34:22.977 に答える
9

dispatchTouchEvent は onInterceptTouchEvent の前に処理します。

次の簡単な例を使用します。

   main = new LinearLayout(this){
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            System.out.println("Event - onInterceptTouchEvent");
            return super.onInterceptTouchEvent(ev);
            //return false; //event get propagated
        }
        @Override
        public boolean dispatchTouchEvent(MotionEvent ev) {
            System.out.println("Event - dispatchTouchEvent");
            return super.dispatchTouchEvent(ev);
            //return false; //event DONT get propagated
        }
    };

    main.setBackgroundColor(Color.GRAY);
    main.setLayoutParams(new LinearLayout.LayoutParams(320,480));    


    viewA = new EditText(this);
    viewA.setBackgroundColor(Color.YELLOW);
    viewA.setTextColor(Color.BLACK);
    viewA.setTextSize(16);
    viewA.setLayoutParams(new LinearLayout.LayoutParams(320,80));
    main.addView(viewA);

    setContentView(main);

ログは次のようになります。

I/System.out(25900): Event - dispatchTouchEvent
I/System.out(25900): Event - onInterceptTouchEvent

したがって、これら 2 つのハンドラーを使用している場合は、dispatchTouchEvent を使用して最初のインスタンスでイベントを処理します。これは onInterceptTouchEvent に移動します。

もう 1 つの違いは、dispatchTouchEvent が「false」を返す場合、イベントは子 (この場合は EditText) に伝達されないのに対し、onInterceptTouchEvent で false を返す場合、イベントは引き続き EditText にディスパッチされることです。

于 2012-09-28T09:27:14.160 に答える
4

ViewGroupサブクラス内の次のコードは、その親コン​​テナーがタッチイベントを受信できないようにします。

  @Override
  public boolean dispatchTouchEvent(MotionEvent ev) {
    // Normal event dispatch to this container's children, ignore the return value
    super.dispatchTouchEvent(ev);

    // Always consume the event so it is not dispatched further up the chain
    return true;
  }

これをカスタムオーバーレイで使用して、背景ビューがタッチイベントに応答しないようにしました。

于 2012-08-22T01:36:16.553 に答える
4

このビデオhttps://www.youtube.com/watch?v=SYoN-OvdZ3M&list=PLonJJ3BVjZW6CtAMbJz1XD8ELUs1KXaTD&index=19と次の 3 つのビデオで答えを見つけることができます。すべてのタッチ イベントは非常によく説明されています。非常に明確で、例が豊富です。

于 2015-01-08T16:04:09.593 に答える
2

主な違い:

•Activity.dispatchTouchEvent(MotionEvent) - これにより、Activity はウィンドウにディスパッチされる前にすべてのタッチ イベントをインターセプトできます。
•ViewGroup.onInterceptTouchEvent(MotionEvent) - これにより、ViewGroup は子ビューにディスパッチされるイベントを監視できます。

于 2012-03-06T14:59:30.590 に答える
-1

小さな答え:

onInterceptTouchEvent は setOnTouchListener の前に来ます。

于 2015-09-25T18:33:20.190 に答える