Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android中的onInterceptTouchEvent與onTouchEvent

Android中的onInterceptTouchEvent與onTouchEvent

編輯:關於Android編程

在android中,每一次touch事件基本包含ACTION_DOWN,ACTION_MOVE,ACTION_UP等一系列action。這裡需要先明確一下這一次touch事件跟一個ACTION的區別。touch事件是包含ACTION_DOWN,ACTION_MOVE,ACTION_UP等action的,一次touch事件一般會先觸發一次ACION_DOWN的action,緊接著是ACTION_MOVE,手指抬起後觸發ACTION_UP,那麼這一次的touch事件就結束了。當下一個ACTION_DOWN到來時,可能就意味著這是一個新的touch事件了。 當手指觸摸到屏幕時,系統就會調用相應View的onTouchEvent,並傳入一系列的action。當有多個層級的View時,在父層級允許的情況下,這個action會一直向下傳遞直到遇到最深層的View。所以touch事件最先調用的是最底層View的onTouchEent,如果View的onTouchEvent接收到某個touch action並作了相應處理,最後有兩種返回方式return true和return false;return true會告訴系統當前的View需要處理這次的touch事件,以後的系統發出的ACTION_MOVE,ACTION_UP還是需要繼續監聽並接收的,而且這次的action已經被處理掉了,父層的View是不可能出發onTouchEvent了。所以每一個action最多只能有一個onTouchEvent接口返回true。如果return false,便會通知系統,當前View不關心這一次的touch事件,此時這個action會傳向父級,調用父級View的onTouchEvent。但是這一次的touch事件之後發出的任何action,該View都不會再接受,onTouchEvent在這一次的touch事件中再也不會觸發,也就是說一旦View返回false,那麼之後的ACTION_MOVE,ACTION_UP等ACTION就不會在傳入這個View,但是下一次touch事件的action還是會傳進來的。 前面說了底層的View能夠接收到這次的事件有一個前提條件:在父層級允許的情況下。假設不改變父層級的dispatch方法,在系統調用底層onTouchEvent之前會先調用父View的onInterceptTouchEvent方法判斷,父層View是不是要截獲本次touch事件之後的action。如果onInterceptTouchEvent返回了true,那麼本次touch事件之後的所有action都不會再向深層的View傳遞,統統都會傳給負層View的onTouchEvent,就是說父層已經截獲了這次touch事件,之後的action也不必詢問onInterceptTouchEvent,在這次的touch事件之後發出的action時onInterceptTouchEvent不會再次調用,知道下一次touch事件的來臨。如果onInterceptTouchEvent返回false,那麼本次action將發送給更深層的View,並且之後的每一次action都會詢問父層的onInterceptTouchEvent需不需要截獲本次touch事件。只有ViewGroup才有onInterceptTouchEvent方法,因為一個普通的View肯定是位於最深層的View,touch事件能夠傳到這裡已經是最後一站了,肯定會調用View的onTouchEvent。 對於底層的View來說,有一種方法可以阻止父層的View截獲touch事件,就是調用getParent().requestDisallowInterceptTouchEvent(true);方法。一旦底層View收到touch的action後調用這個方法那麼父層View就不會再調用onInterceptTouchEvent了,也無法截獲以後的action。 用例子總結一下onInterceptTouchEvent和onTouchEvent的調用順序: 假設最高層View叫OuterLayout,中間層View叫InnerLayout,最底層View叫MyVIew。調用順序是這樣的(假設各個函數返回的都是false) OuterLayout.onInterceptTouchEvent->InnerLayout.onInterceptTouchEvent->MyView.onTouchEvent->InnerLayout.onTouchEvent->OuterLayout.onTouchEvent。 layout.xml [html]  <com.example.ontouchevent.OuterLayout xmlns:android="http://schemas.android.com/apk/res/android"       xmlns:tools="http://schemas.android.com/tools"       android:layout_width="match_parent"       android:layout_height="match_parent"       android:background="#ffff0000" >          <com.example.ontouchevent.InnerLayout           android:layout_width="match_parent"           android:layout_height="200dip"           android:background="#ffffff00" >              <com.example.ontouchevent.MyView               android:layout_width="match_parent"               android:layout_height="100dip"               android:background="#ff00ffff" />          </com.example.ontouchevent.InnerLayout>      </com.example.ontouchevent.OuterLayout>   OunterLayout.java [java]  package com.example.ontouchevent;      import android.content.Context;   import android.util.AttributeSet;   import android.util.Log;   import android.view.MotionEvent;   import android.widget.FrameLayout;      public class OuterLayout extends FrameLayout {          public OuterLayout(Context context) {           super(context);           // TODO Auto-generated constructor stub       }          public OuterLayout(Context context, AttributeSet attrs) {           super(context, attrs);           // TODO Auto-generated constructor stub       }          public OuterLayout(Context context, AttributeSet attrs, int defStyle) {           super(context, attrs, defStyle);           // TODO Auto-generated constructor stub       }          @Override       public boolean onInterceptTouchEvent(MotionEvent ev) {           boolean res = false;           Log.d("TestOnTouchEvent", "OuterLayout onInterceptTouchEvent event:" + ev.getAction() + " returned:" + res);           return res;       }          @Override       public boolean onTouchEvent(MotionEvent event) {           boolean res = true;           Log.d("TestOnTouchEvent", "OuterLayout onTouchEvent event:" + event.getAction() + " returned:" + res);           return res;       }      }   InnerLayout.java [java]   package com.example.ontouchevent;      import android.content.Context;   import android.util.AttributeSet;   import android.util.Log;   import android.view.MotionEvent;   import android.widget.FrameLayout;      public class InnerLayout extends FrameLayout {          public InnerLayout(Context context) {           super(context);           // TODO Auto-generated constructor stub       }          public InnerLayout(Context context, AttributeSet attrs) {           super(context, attrs);           // TODO Auto-generated constructor stub       }          public InnerLayout(Context context, AttributeSet attrs, int defStyle) {           super(context, attrs, defStyle);           // TODO Auto-generated constructor stub       }          @Override       protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {           super.onMeasure(widthMeasureSpec, heightMeasureSpec);       }          @Override       public boolean onInterceptTouchEvent(MotionEvent ev) {           boolean res = false;           Log.d("TestOnTouchEvent", "InnerLayout onInterceptTouchEvent event:" + ev.getAction() + " returned:" + res);           return res;       }          @Override       public boolean onTouchEvent(MotionEvent event) {           boolean res = false;           Log.d("TestOnTouchEvent", "InnerLayout onTouchEvent event:" + event.getAction() + " returned:" + res);           return res;       }      }   MyView.java [html]   package com.example.ontouchevent;      import android.content.Context;   import android.util.AttributeSet;   import android.util.Log;   import android.view.MotionEvent;   import android.view.View;      public class MyView extends View {          public MyView(Context context) {           super(context);       }          public MyView(Context context, AttributeSet attrs) {           super(context, attrs);       }          public MyView(Context context, AttributeSet attrs, int defStyle) {           super(context, attrs, defStyle);       }          @Override       public boolean onTouchEvent(MotionEvent event) {           boolean res = false;   www.2cto.com         Log.d("TestOnTouchEvent", "MyView onTouchEvent event:" + event.getAction() + " returned:" + res);           return res;       }      }   假設只有OunterLayout的onTouchEvent返回true,其他所有全返回false,log如下 [java]   D/TestOnTouchEvent(11121): OuterLayout onInterceptTouchEvent event:0 returned:false   D/TestOnTouchEvent(11121): InnerLayout onInterceptTouchEvent event:0 returned:false   D/TestOnTouchEvent(11121): MyView onTouchEvent event:0 returned:false   D/TestOnTouchEvent(11121): InnerLayout onTouchEvent event:0 returned:false   D/TestOnTouchEvent(11121): OuterLayout onTouchEvent event:0 returned:true   D/TestOnTouchEvent(11121): OuterLayout onTouchEvent event:2 returned:true   D/TestOnTouchEvent(11121): OuterLayout onTouchEvent event:2 returned:true   D/TestOnTouchEvent(11121): OuterLayout onTouchEvent event:2 returned:true   D/TestOnTouchEvent(11121): OuterLayout onTouchEvent event:2 returned:true   D/TestOnTouchEvent(11121): OuterLayout onTouchEvent event:1 returned:true     0是ACTION_DOWN,1是ACTION_MOVE,2是ACTION_UP。 可以看到第一個action,會先向下詢問是否處理本次的touch事件,每個View接到action後會先判斷需不需要截獲,不截獲繼續向下傳遞,然後在以相反的順序詢問需不需要處理,直到action被某個View處理,且如果不處理這次的action,那麼本次touch事件之後的其他action都沒有機會處理了。   如果InnerLayout的onIntercepterTouchEvent和onTouchEvent都返回true,log如下: [java]   D/TestOnTouchEvent( 2265): OuterLayout onInterceptTouchEvent event:0 returned:false   D/TestOnTouchEvent( 2265): InnerLayout onInterceptTouchEvent event:0 returned:true   D/TestOnTouchEvent( 2265): InnerLayout onTouchEvent event:0 returned:true   D/TestOnTouchEvent( 2265): OuterLayout onInterceptTouchEvent event:2 returned:false   D/TestOnTouchEvent( 2265): InnerLayout onTouchEvent event:2 returned:true   D/TestOnTouchEvent( 2265): OuterLayout onInterceptTouchEvent event:2 returned:false   D/TestOnTouchEvent( 2265): InnerLayout onTouchEvent event:2 returned:true   D/TestOnTouchEvent( 2265): OuterLayout onInterceptTouchEvent event:2 returned:false   D/TestOnTouchEvent( 2265): InnerLayout onTouchEvent event:2 returned:true   D/TestOnTouchEvent( 2265): OuterLayout onInterceptTouchEvent event:2 returned:false   D/TestOnTouchEvent( 2265): InnerLayout onTouchEvent event:2 returned:true   D/TestOnTouchEvent( 2265): OuterLayout onInterceptTouchEvent event:2 returned:false   D/TestOnTouchEvent( 2265): InnerLayout onTouchEvent event:2 returned:true   D/TestOnTouchEvent( 2265): OuterLayout onInterceptTouchEvent event:2 returned:false   D/TestOnTouchEvent( 2265): InnerLayout onTouchEvent event:2 returned:true   D/TestOnTouchEvent( 2265): OuterLayout onInterceptTouchEvent event:2 returned:false   D/TestOnTouchEvent( 2265): InnerLayout onTouchEvent event:2 returned:true   D/TestOnTouchEvent( 2265): OuterLayout onInterceptTouchEvent event:2 returned:false   D/TestOnTouchEvent( 2265): InnerLayout onTouchEvent event:2 returned:true   D/TestOnTouchEvent( 2265): OuterLayout onInterceptTouchEvent event:2 returned:false   D/TestOnTouchEvent( 2265): InnerLayout onTouchEvent event:2 returned:true   D/TestOnTouchEvent( 2265): OuterLayout onInterceptTouchEvent event:2 returned:false   D/TestOnTouchEvent( 2265): InnerLayout onTouchEvent event:2 returned:true   D/TestOnTouchEvent( 2265): OuterLayout onInterceptTouchEvent event:2 returned:false   D/TestOnTouchEvent( 2265): InnerLayout onTouchEvent event:2 returned:true   D/TestOnTouchEvent( 2265): OuterLayout onInterceptTouchEvent event:1 returned:false   D/TestOnTouchEvent( 2265): InnerLayout onTouchEvent event:1 returned:true   可以看到OuterLayout每次都會調用onInterceptTouchEvent判斷是否截獲這次的touch事件,同時能夠看到,InnerLayout截獲了touch事件,所以以後的action都不會傳給MyView,還有一點是InnerLayout處理了所有的action,那麼action也不會再上傳到父層  
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved