onInterceptTouchEvent和onTouchEvent调用时序
onInterceptTouchEvent()是ViewGroup的一個方法,目的是在系統(tǒng)向該ViewGroup及其各個childView觸發(fā)onTouchEvent()之前對相關(guān)事件進(jìn)行一次攔截,Android這么設(shè)計(jì)的想法也很好理解,由于ViewGroup會包含若干childView,因此需要能夠統(tǒng)一監(jiān)控各種touch事件的機(jī)會,因此純粹的不能包含子view的控件是沒有這個方法的,如LinearLayout就有,TextView就沒有。?
onInterceptTouchEvent()使用也很簡單,如果在ViewGroup里覆寫了該方法,那么就可以對各種touch事件加以攔截。但是如何攔截,是否所有的touch事件都需要攔截則是比較復(fù)雜的,touch事件在onInterceptTouchEvent()和onTouchEvent以及各個childView間的傳遞機(jī)制完全取決于onInterceptTouchEvent()和onTouchEvent()的返回值。并且,針對down事件處理的返回值直接影響到后續(xù)move和up事件的接收和傳遞。?
關(guān)于返回值的問題,基本規(guī)則很清楚,如果return true,那么表示該方法消費(fèi)了此次事件,如果return false,那么表示該方法并未處理完全,該事件仍然需要以某種方式傳遞下去繼續(xù)等待處理。
SDK給出的說明如下:
- You will receive the down event here.
- The down event will be handled either by a child of this view group, or given to your own onTouchEvent() method to handle; this means you should implement onTouchEvent() to return true, so you will continue to see the rest of the gesture (instead of looking for a parent view to handle it). Also, by returning true from onTouchEvent(), you will not receive any following events in onInterceptTouchEvent() and all touch processing must happen in onTouchEvent() like normal.
- For as long as you return false from this function, each following event (up to and including the final up) will be delivered first here and then to the target's onTouchEvent().
- If you return true from here, you will not receive any following events: the target view will receive the same event but with the action?ACTION_CANCEL, and all further events will be delivered to your onTouchEvent() method and no longer appear here.
?
由于onInterceptTouchEvent()的機(jī)制比較復(fù)雜,上面的說明寫的也比較復(fù)雜,總結(jié)一下,基本的規(guī)則是:
?
下面用一個簡單的實(shí)驗(yàn)說明上述復(fù)雜的規(guī)則。視圖自底向上共3層,其中LayoutView1和LayoutView2就是LinearLayout,?MyTextView就是TextView:
對應(yīng)的xml布局文件如下:
<?xml?version="1.0"?encoding="utf-8"?>
<com.touchstudy.LayoutView1?xmlns:android="http://schemas.android.com/apk/res/android"
????android:orientation="vertical"
????android:layout_width="fill_parent"
????android:layout_height="fill_parent"?>
????<com.touchstudy.LayoutView2
????????android:orientation="vertical"
????????android:layout_width="fill_parent"
????????android:layout_height="fill_parent"
????????android:gravity="center">
???????<com.touchstudy.MyTextView?
????????????android:layout_width="wrap_content"
????????????android:layout_height="wrap_content"
????????????android:id="@+id/tv"
????????????android:text="AB"
????????????android:textSize="40sp"
????????????android:textStyle="bold"
????????????android:background="#FFFFFF"
????????????android:textColor="#0000FF"/>
???</com.touchstudy.LayoutView2>
</com.touchstudy.LayoutView1>
?
下面看具體情況:
------------------------------------------------------------------------------------------------------------------------------
04-11 03:58:42.620: DEBUG/LayoutView1(614): onInterceptTouchEvent action:ACTION_DOWN
04-11 03:58:42.620: DEBUG/LayoutView2(614): onInterceptTouchEvent action:ACTION_DOWN
04-11 03:58:42.620: DEBUG/MyTextView(614): onTouchEvent action:ACTION_DOWN
04-11 03:58:42.800: DEBUG/LayoutView1(614): onInterceptTouchEvent action:ACTION_MOVE
04-11 03:58:42.800: DEBUG/LayoutView2(614): onInterceptTouchEvent action:ACTION_MOVE
04-11 03:58:42.800: DEBUG/MyTextView(614): onTouchEvent action:ACTION_MOVE
…… //省略過多的ACTION_MOVE
04-11 03:58:43.130: DEBUG/LayoutView1(614): onInterceptTouchEvent action:ACTION_UP
04-11 03:58:43.130: DEBUG/LayoutView2(614): onInterceptTouchEvent action:ACTION_UP
04-11 03:58:43.150: DEBUG/MyTextView(614): onTouchEvent action:ACTION_UP
------------------------------------------------------------------------------------------------------------------------------
這是最常見的情況,onInterceptTouchEvent并沒有做任何改變事件傳遞時序的操作,效果上和沒有覆寫該方法是一樣的。可以看到,各種事件的傳遞本身是自底向上的,次序是:LayoutView1->LayoutView2->MyTextView。注意,在onInterceptTouchEvent均返回false時,LayoutView1和LayoutView2的onTouchEvent并不會收到事件,而是最終傳遞給了MyTextView。
?
MyTextView的onTouchEvent()處理事件返回true
------------------------------------------------------------------------------------------------------------------------------
04-11 03:09:27.589: DEBUG/LayoutView1(446): onInterceptTouchEvent action:ACTION_DOWN
04-11 03:09:27.589: DEBUG/LayoutView1(446): onTouchEvent action:ACTION_DOWN
04-11 03:09:27.629: DEBUG/LayoutView1(446): onTouchEvent action:ACTION_MOVE
04-11 03:09:27.689: DEBUG/LayoutView1(446): onTouchEvent action:ACTION_MOVE
…… //省略過多的ACTION_MOVE
04-11 03:09:27.959: DEBUG/LayoutView1(446): onTouchEvent action:ACTION_UP
------------------------------------------------------------------------------------------------------------------------------
從Log可以看到,由于LayoutView1在攔截第一次down事件時return true,所以后續(xù)的事件(包括第一次的down)將由LayoutView1本身處理,事件不再傳遞下去。
?
MyTextView的onTouchEvent()處理事件返回false
LayoutView2的onTouchEvent()處理事件返回true
----------------------------------------------------------------------------------------------------------------------------
04-11 09:50:21.147: DEBUG/LayoutView1(301): onInterceptTouchEvent action:ACTION_DOWN
04-11 09:50:21.147: DEBUG/LayoutView2(301): onInterceptTouchEvent action:ACTION_DOWN
04-11 09:50:21.147: DEBUG/MyTextView(301): onTouchEvent action:ACTION_DOWN
04-11 09:50:21.147: DEBUG/LayoutView2(301): onTouchEvent action:ACTION_DOWN
04-11 09:50:21.176: DEBUG/LayoutView1(301): onInterceptTouchEvent action:ACTION_MOVE
04-11 09:50:21.176: DEBUG/LayoutView2(301): onTouchEvent action:ACTION_MOVE
04-11 09:50:21.206: DEBUG/LayoutView1(301): onInterceptTouchEvent action:ACTION_MOVE
04-11 09:50:21.217: DEBUG/LayoutView2(301): onTouchEvent action:ACTION_MOVE
…… //省略過多的ACTION_MOVE
04-11 09:50:21.486: DEBUG/LayoutView1(301): onInterceptTouchEvent action:ACTION_UP
04-11 09:50:21.486: DEBUG/LayoutView2(301): onTouchEvent action:ACTION_UP
----------------------------------------------------------------------------------------------------------------------------
可以看到,由于MyTextView在onTouchEvent()中return false,down事件被傳遞給其父view,即LayoutView2的onTouchEvent()方法處理,由于在LayoutView2的onTouchEvent()中return true,所以down事件傳遞并沒有上傳到LayoutView1。注意,后續(xù)的move和up事件均被傳遞給LayoutView2的onTouchEvent()處理,而沒有傳遞給MyTextView。
?
----------------------------------------------------------------------------------------------------------------
應(yīng)大家的要求,我把源代碼貼上,其實(shí)很簡單,就是基礎(chǔ)文件,主要是用來觀察事件的傳遞。
?
主Activity: InterceptTouchStudyActivity.java:
?
public?class?InterceptTouchStudyActivity?extends?Activity {
????static?final?String?TAG?=?"ITSActivity";
??? TextView?tv;
???
????/** Called when the activity is first created. */
????@Override
????public?void?onCreate(Bundle savedInstanceState) {
????????super.onCreate(savedInstanceState);
??????? setContentView(R.layout.layers_touch_pass_test);
??? ?}
?}
?? ? ?LayoutView1.java:
?? ? ?public?class?LayoutView1?extends?LinearLayout {
???? ?private?final?String?TAG?=?"LayoutView1";
?? ??? ?public?LayoutView1(Context context, AttributeSet attrs) {
?????????super(context, attrs);
???????? Log.d(TAG,TAG);
???? }
?
?????@Override
?????public?boolean?onInterceptTouchEvent(MotionEvent ev) {
?????????int?action = ev.getAction();
?????????switch(action){
?????????case?MotionEvent.ACTION_DOWN:
????????????? Log.d(TAG,"onInterceptTouchEvent action:ACTION_DOWN");
//??????????? return true;
??????????????break;
?????????case?MotionEvent.ACTION_MOVE:
????????????? Log.d(TAG,"onInterceptTouchEvent action:ACTION_MOVE");
??????????????break;
?????????case?MotionEvent.ACTION_UP:
????????????? Log.d(TAG,"onInterceptTouchEvent action:ACTION_UP");
??????????????break;
?????????case?MotionEvent.ACTION_CANCEL:
????????????? Log.d(TAG,"onInterceptTouchEvent action:ACTION_CANCEL");
??????????????break;
???????? }
????????
?????????return?false;
???? }
?
?????@Override
?????public?boolean?onTouchEvent(MotionEvent ev) {
?????????int?action = ev.getAction();
?????????switch(action){
?????????case?MotionEvent.ACTION_DOWN:
????????????? Log.d(TAG,"onTouchEvent action:ACTION_DOWN");
??????????????break;
?????????case?MotionEvent.ACTION_MOVE:
????????????? Log.d(TAG,"onTouchEvent action:ACTION_MOVE");
??????????????break;
?????????case?MotionEvent.ACTION_UP:
????????????? Log.d(TAG,"onTouchEvent action:ACTION_UP");
??????????????break;
?????????case?MotionEvent.ACTION_CANCEL:
????????????? Log.d(TAG,"onTouchEvent action:ACTION_CANCEL");
??????????????break;
???????? }
????????
?????????return?true;
???? }
?
?????@Override
?????protected?void?onLayout(boolean?changed,?int?l,?int?t,?int?r,?int?b) {
?????????//?TODO?Auto-generated method stub
?????????super.onLayout(changed, l, t, r, b);
???? }
?
?????@Override
?????protected?void?onMeasure(int?widthMeasureSpec,?int?heightMeasureSpec) {
?????????//?TODO?Auto-generated method stub
?????????super.onMeasure(widthMeasureSpec, heightMeasureSpec);
???? }
}
LayoutView2.java:
public?class?LayoutView2?extends?LinearLayout {
????private?final?String?TAG?=?"LayoutView2";
???
????public?LayoutView2(Context context, AttributeSet attrs) {
???????super(context, attrs);
?????? Log.d(TAG,TAG);
??? }
?
????@Override
????public?boolean?onInterceptTouchEvent(MotionEvent ev) {
???????int?action = ev.getAction();
???????switch(action){
???????case?MotionEvent.ACTION_DOWN:
?????????? Log.d(TAG,"onInterceptTouchEvent action:ACTION_DOWN");
???????????break;
???????case?MotionEvent.ACTION_MOVE:
?????????? Log.d(TAG,"onInterceptTouchEvent action:ACTION_MOVE");
???????????break;
???????case?MotionEvent.ACTION_UP:
?????????? Log.d(TAG,"onInterceptTouchEvent action:ACTION_UP");
???????????break;
???????case?MotionEvent.ACTION_CANCEL:
?????????? Log.d(TAG,"onInterceptTouchEvent action:ACTION_CANCEL");
???????????break;
?????? }
??????
???????return?false;
??? }
?
????@Override
????public?boolean?onTouchEvent(MotionEvent ev) {
???????int?action = ev.getAction();
???????switch(action){
???????case?MotionEvent.ACTION_DOWN:
?????????? Log.d(TAG,"onTouchEvent action:ACTION_DOWN");
???????????break;
???????case?MotionEvent.ACTION_MOVE:
?????????? Log.d(TAG,"onTouchEvent action:ACTION_MOVE");
???????????break;
???????case?MotionEvent.ACTION_UP:
?????????? Log.d(TAG,"onTouchEvent action:ACTION_UP");
???????????break;
???????case?MotionEvent.ACTION_CANCEL:
?????????? Log.d(TAG,"onTouchEvent action:ACTION_CANCEL");
???????????break;
?????? }
??????
???????return?true;
??? }?
}
MyTextView.java:
public?class?MyTextView?extends?TextView {
????private?final?String?TAG?=?"MyTextView";
???
????public?MyTextView(Context context, AttributeSet attrs) {
???????super(context, attrs);
?????? Log.d(TAG,TAG);
??? }
?
????@Override
????public?boolean?onTouchEvent(MotionEvent ev) {
???????int?action = ev.getAction();
???????switch(action){
???????case?MotionEvent.ACTION_DOWN:
?????????? Log.d(TAG,"onTouchEvent action:ACTION_DOWN");
???????????break;
???????case?MotionEvent.ACTION_MOVE:
?????????? Log.d(TAG,"onTouchEvent action:ACTION_MOVE");
???????????break;
???????case?MotionEvent.ACTION_UP:
?????????? Log.d(TAG,"onTouchEvent action:ACTION_UP");
???????????break;
???????case?MotionEvent.ACTION_CANCEL:
?????????? Log.d(TAG,"onTouchEvent action:ACTION_CANCEL");
???????????break;
?????? }
??????
???????return?false;
??? }
???
????public?void?onClick(View v) {
?????? Log.d(TAG,?"onClick");
??? }
???
????public?boolean?onLongClick(View v) {
?????? Log.d(TAG,?"onLongClick");
???????return?false;
??? }
}
?
#?re: onInterceptTouchEvent和onTouchEvent調(diào)用時序 2011-08-19 09:25 | 米其林的微笑博主,你好,我想請問一下onTouchEvent的事件是是由childView傳到 parentView,還是由parentView傳到childView?你說由底向上,但是標(biāo)志的順序又很奇怪,底是指父親節(jié)點(diǎn),還是?如果我在 parentView想接收down事件,在childView接收down,up,move的事件,哪些函數(shù)的返回值,該怎么處理。請指點(diǎn),謝謝 了。??回復(fù)??更多評論
?? #?re: onInterceptTouchEvent和onTouchEvent調(diào)用時序[未登錄] 2011-08-19 09:30 | tigertian
@米其林的微笑
onTouchEvent事件是由childView傳到parentView。
你 在parentView想接收down事件的話,childView在收到事件后onTouchEvent方法都要返回false,這樣讓 parentView也能收到事件,同時parentView中只捕捉ACTION_DOWN,在childView中捕捉三個事件。??回復(fù)??更多評論
?? #?re: onInterceptTouchEvent和onTouchEvent調(diào)用時序 2011-08-20 00:30 | 米其林的微笑
@tigertian
謝謝你的回答。那childView在收到事件后onTouchEvent方法都要返回false,down,up,move的事件會響應(yīng)么?如果在parentView中想處理up 事件呢。我現(xiàn)在怎么處理都是只有一個有響應(yīng)。??回復(fù)??更多評論
?? #?re: onInterceptTouchEvent和onTouchEvent調(diào)用時序 2012-02-07 11:05 | 周歡
@tigertian
你在parentView想接收down事件的話,childView在收到 事件后onTouchEvent方法都要返回false,這樣讓parentView也能收到事件,同時Child中只捕捉ACTION_DOWN,在 Parent中捕捉三個事件.樓主可能說反了??回復(fù)??更多評論
??
#?re: onInterceptTouchEvent和onTouchEvent調(diào)用時序 2012-09-07 13:35 | 248933223@qq.com
其實(shí)這是設(shè)計(jì)模式中比較常見的一個模式,叫責(zé)任鏈模式,類似filter的功能??回復(fù)??更多評論
?
FromAddress
總結(jié)
以上是生活随笔為你收集整理的onInterceptTouchEvent和onTouchEvent调用时序的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: .NET大型Web站点StackOver
- 下一篇: 使用PHP读取和创建txt,doc,xl