用到的例子工程介紹:在viewGroup中加入子view,即LinerLayout中存在一子view,在MyLinerLayout中重寫了 dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent
在MyTestView中重寫了dispatchTouchEvent、onTouchEvent。
分別研究各種返回值對事件傳遞的路徑影響。
MyLinerLayout.java
- public class MyLinearLayout extends LinearLayout implements View.OnClickListener,View.OnLongClickListener {
- private final static String TAG = "TouchEvent";
- public MyLinearLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
- // TODO Auto-generated constructor stub
- Log.v(TAG , "MyLinearLayout");
- //this.setOnClickListener(this);
- //this.setOnLongClickListener(this);
- }
- public void onClick(View v) {
- // TODO Auto-generated method stub
- Log.v(TAG , "MyLinearLayout onClick [" + "] test.................view:"+v.getId() );
- }
- @Override
- public boolean onLongClick(View v) {
- // TODO Auto-generated method stub
- boolean b = true;
- Log.v(TAG , "MyLinearLayout onLongClick [" + "] test.................view:"+v.getId() +"return :"+b);
- return true;
- }
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev) {
- int action = ev.getAction();
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- Log.d(TAG, "MyLinearLayout --dispatchTouchEvent action:ACTION_DOWN");
- break;
- case MotionEvent.ACTION_MOVE:
- Log.d(TAG, "MyLinearLayout --dispatchTouchEvent action:ACTION_MOVE");
- return false;
- //break;
- case MotionEvent.ACTION_UP:
- Log.d(TAG, "MyLinearLayout --dispatchTouchEvent action:ACTION_UP");
- break;
- case MotionEvent.ACTION_CANCEL:
- Log.d(TAG, "MyLinearLayout --dispatchTouchEvent action:ACTION_CANCEL");
- break;
- }
- // Log.v(TAG , "dispatchTouchEvent "+super.dispatchTouchEvent(ev));
- boolean b = super.dispatchTouchEvent(ev);
- //boolean b = false;
- Log.v(TAG , "MyLinearLayout --dispatchTouchEvent ["+action+ "] test.................return:"+b);
- return b;
- }
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- int action = ev.getAction();
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- Log.d(TAG, "MyLinearLayout --onInterceptTouchEvent action:ACTION_DOWN");
- break;
- case MotionEvent.ACTION_MOVE:
- Log.d(TAG, "MyLinearLayout --onInterceptTouchEvent action:ACTION_MOVE");
- break;
- case MotionEvent.ACTION_UP:
- Log.d(TAG, "MyLinearLayout --onInterceptTouchEvent action:ACTION_UP");
- break;
- case MotionEvent.ACTION_CANCEL:
- Log.d(TAG, "MyLinearLayout --onInterceptTouchEvent action:ACTION_CANCEL");
- break;
- }
- //boolean b = super.onInterceptTouchEvent(ev);
- boolean b = true;
- Log.v(TAG , "MyLinearLayout --onInterceptTouchEvent ["+action+ "] test.................return: "+b);
- return b;
- }
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- int action = ev.getAction();
- //boolean b = super.onTouchEvent(ev);
- boolean b = true;
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- Log.d(TAG, "MyLinearLayout---onTouchEvent action:ACTION_DOWN");
- break;
- case MotionEvent.ACTION_MOVE:
- Log.d(TAG, "MyLinearLayout---onTouchEvent action:ACTION_MOVE");
- break;
- case MotionEvent.ACTION_UP:
- Log.d(TAG, "MyLinearLayout---onTouchEvent action:ACTION_UP");
- break;
- case MotionEvent.ACTION_CANCEL:
- Log.d(TAG, "MyLinearLayout---onTouchEvent action:ACTION_CANCEL");
- break;
- }
- Log.v(TAG , "MyLinearLayout --onTouchEvent ["+action+ "] test.................return: "+b);
- return b;
- }
- }
public class MyLinearLayout extends LinearLayout implements View.OnClickListener,View.OnLongClickListener {
private final static String TAG = "TouchEvent";
public MyLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
Log.v(TAG , "MyLinearLayout");
//this.setOnClickListener(this);
//this.setOnLongClickListener(this);
}
public void onClick(View v) {
// TODO Auto-generated method stub
Log.v(TAG , "MyLinearLayout onClick [" + "] test.................view:"+v.getId() );
}
@Override
public boolean onLongClick(View v) {
// TODO Auto-generated method stub
boolean b = true;
Log.v(TAG , "MyLinearLayout onLongClick [" + "] test.................view:"+v.getId() +"return :"+b);
return true;
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
Log.d(TAG, "MyLinearLayout --dispatchTouchEvent action:ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.d(TAG, "MyLinearLayout --dispatchTouchEvent action:ACTION_MOVE");
return false;
//break;
case MotionEvent.ACTION_UP:
Log.d(TAG, "MyLinearLayout --dispatchTouchEvent action:ACTION_UP");
break;
case MotionEvent.ACTION_CANCEL:
Log.d(TAG, "MyLinearLayout --dispatchTouchEvent action:ACTION_CANCEL");
break;
}
// Log.v(TAG , "dispatchTouchEvent "+super.dispatchTouchEvent(ev));
boolean b = super.dispatchTouchEvent(ev);
//boolean b = false;
Log.v(TAG , "MyLinearLayout --dispatchTouchEvent ["+action+ "] test.................return:"+b);
return b;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
Log.d(TAG, "MyLinearLayout --onInterceptTouchEvent action:ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.d(TAG, "MyLinearLayout --onInterceptTouchEvent action:ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.d(TAG, "MyLinearLayout --onInterceptTouchEvent action:ACTION_UP");
break;
case MotionEvent.ACTION_CANCEL:
Log.d(TAG, "MyLinearLayout --onInterceptTouchEvent action:ACTION_CANCEL");
break;
}
//boolean b = super.onInterceptTouchEvent(ev);
boolean b = true;
Log.v(TAG , "MyLinearLayout --onInterceptTouchEvent ["+action+ "] test.................return: "+b);
return b;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
int action = ev.getAction();
//boolean b = super.onTouchEvent(ev);
boolean b = true;
switch (action) {
case MotionEvent.ACTION_DOWN:
Log.d(TAG, "MyLinearLayout---onTouchEvent action:ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.d(TAG, "MyLinearLayout---onTouchEvent action:ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.d(TAG, "MyLinearLayout---onTouchEvent action:ACTION_UP");
break;
case MotionEvent.ACTION_CANCEL:
Log.d(TAG, "MyLinearLayout---onTouchEvent action:ACTION_CANCEL");
break;
}
Log.v(TAG , "MyLinearLayout --onTouchEvent ["+action+ "] test.................return: "+b);
return b;
}
}
- TextView.java
TextView.java
- package com.lee.stony;
- import android.content.Context;
- import android.util.AttributeSet;
- import android.util.Log;
- import android.view.MotionEvent;
- import android.widget.SimpleAdapter.ViewBinder;
- import android.widget.TextView;
- import android.view.View;
- public class MyTestView extends TextView{
- public static final String TAG = "TouchEvent";
- public MyTestView(Context context, AttributeSet attrs) {
- super(context, attrs);
- // TODO Auto-generated constructor stub
- Log.v(TAG, "MyTestView");
- /*this.setOnClickListener(this);
- this.setOnLongClickListener(this);*/
- }
- /*@Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- Log.v(TAG , "MyTestView onClick [" + "] test.................view:"+v.getId() );
- }
- @Override
- public boolean onLongClick(View v) {
- // TODO Auto-generated method stub
- boolean b = true;
- Log.v(TAG , "MyTestView onLongClick [" + "] test.................view:"+v.getId() +"return :"+b);
- return true;
- }
- */
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev) {
- int action = ev.getAction();
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- Log.d(TAG, "MyTestView-- dispatchTouchEvent action:ACTION_DOWN");
- break;
- case MotionEvent.ACTION_MOVE:
- Log.d(TAG, "MyTestView-- dispatchTouchEvent action:ACTION_MOVE");
- break;
- case MotionEvent.ACTION_UP:
- Log.d(TAG, "MyTestView-- dispatchTouchEvent action:ACTION_UP");
- break;
- case MotionEvent.ACTION_CANCEL:
- Log.d(TAG, "MyTestView-- dispatchTouchEvent action:ACTION_CANCEL");
- break;
- }
- boolean b = super.dispatchTouchEvent(ev);
- //boolean b = true;
- Log.v(TAG , "MyTestView dispatchTouchEvent ["+action+ "] test.................return:"+b);
- return b;
- }
- @Override
- public boolean onTouchEvent(MotionEvent ev) {
- boolean b = super.onTouchEvent(ev);
- int action = ev.getAction();
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- Log.d(TAG, "MyTestView-- ---onTouchEvent action:ACTION_DOWN");
- break;
- case MotionEvent.ACTION_MOVE:
- Log.d(TAG, "MyTestView-- ---onTouchEvent action:ACTION_MOVE");
- break;
- case MotionEvent.ACTION_UP:
- Log.d(TAG, "MyTestView-- ---onTouchEvent action:ACTION_UP");
- break;
- case MotionEvent.ACTION_CANCEL:
- Log.d(TAG, "MyTestView-- ---onTouchEvent action:ACTION_CANCEL");
- break;
- }
- //boolean b = true;
- Log.v(TAG , "MyTestView onTouchEvent ["+action+ "] test.................return:"+b);
- return b;
- }
- }
package com.lee.stony;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.widget.SimpleAdapter.ViewBinder;
import android.widget.TextView;
import android.view.View;
public class MyTestView extends TextView{
public static final String TAG = "TouchEvent";
public MyTestView(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
Log.v(TAG, "MyTestView");
/*this.setOnClickListener(this);
this.setOnLongClickListener(this);*/
}
/*@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Log.v(TAG , "MyTestView onClick [" + "] test.................view:"+v.getId() );
}
@Override
public boolean onLongClick(View v) {
// TODO Auto-generated method stub
boolean b = true;
Log.v(TAG , "MyTestView onLongClick [" + "] test.................view:"+v.getId() +"return :"+b);
return true;
}
*/
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
Log.d(TAG, "MyTestView-- dispatchTouchEvent action:ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.d(TAG, "MyTestView-- dispatchTouchEvent action:ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.d(TAG, "MyTestView-- dispatchTouchEvent action:ACTION_UP");
break;
case MotionEvent.ACTION_CANCEL:
Log.d(TAG, "MyTestView-- dispatchTouchEvent action:ACTION_CANCEL");
break;
}
boolean b = super.dispatchTouchEvent(ev);
//boolean b = true;
Log.v(TAG , "MyTestView dispatchTouchEvent ["+action+ "] test.................return:"+b);
return b;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
boolean b = super.onTouchEvent(ev);
int action = ev.getAction();
switch (action) {
case MotionEvent.ACTION_DOWN:
Log.d(TAG, "MyTestView-- ---onTouchEvent action:ACTION_DOWN");
break;
case MotionEvent.ACTION_MOVE:
Log.d(TAG, "MyTestView-- ---onTouchEvent action:ACTION_MOVE");
break;
case MotionEvent.ACTION_UP:
Log.d(TAG, "MyTestView-- ---onTouchEvent action:ACTION_UP");
break;
case MotionEvent.ACTION_CANCEL:
Log.d(TAG, "MyTestView-- ---onTouchEvent action:ACTION_CANCEL");
break;
}
//boolean b = true;
Log.v(TAG , "MyTestView onTouchEvent ["+action+ "] test.................return:"+b);
return b;
}
}
1、 android中用於事件處理的方法和類主要有如下幾種:
onTouchEvent
onInterceptTouchEvent//在viewgroup纔有的方法,用於分發子view
dispatchTouchEvent
實現View.OnClickListener 的onClick
實現View.OnLongClickListener 的 onLongClick
實現View.OnTouchClickListener 的 onTouch
說明:在事件處理中,其實我們一般遇到事件有3中,分別是down、move、up,其中move事件在一個操作中(這裏說的一個操作就是用戶與屏幕的交互,即由down到up的動作序列)可能會發生多次,但是,我們認爲一個動作序列會包含以上三種事件,因此,在事件處理中就是要處理好這個過程,而最重要的就是down事件,這是一個動作序列的起始,沒有down談不上後面的事件了。所以,我們把消耗down事件的類當做是這個動作序列的最終載體。
2、 各種返回值的含義和作用
(1)dispatchTouchEvent()
返回值 |
作用 |
True |
繼續接受動作序列中的後續事件,如move、move、up |
False |
不接受動作序列中的後續事件,因此本次後續操作不起作用,如:down後返回false,則move和up都不會被接受,只能接受下個動作。這裏爲什麼特別指定的down事件呢,因爲如果down返回true,說明後續事件會被傳遞於此,但是move返回false呢?哈哈,這個就不會影響了,因此說down纔是關鍵 |
總結:此方法一般用於初步處理事件,因爲動作是由此分發,所以通常會調用super.dispatchTouchEvent。這樣就會繼續調用onInterceptTouchEvent,再由onInterceptTouchEvent決定事件流向。
例子:
當在DispatchTouchEvent中調用了super.dispatchTouchEvent,則會繼續向下執行到onInterceptTouchEvent方法。
(2)onInterceptTouchEvent():
返回值 |
作用 |
True |
事件會傳遞到自己的onTouchEvent() |
False |
傳遞到下一個view的dispatchTouchEvent() |
例子1:
類 |
方法 |
返回值 |
說明 |
MyLinerLayout |
dispatchTouchEvent |
True |
調用super. dispatchTouchEvent |
onInterceptTouchEvent |
true |
True 則調用自己的onTouchEvent |
|
onTouchEvent |
true |
True 則後續動作序列直接發到此處,不經過onInterceptTouchEvent |
|
MyTestView |
dispatchTouchEvent |
True |
這裏因爲MyLinerLayout. onInterceptTouchEvent返回true,因此不會傳遞於此 |
onTouchEvent |
True |
|
圖:點擊父和子view效果一樣
說明:Down事件在MyLinerLayout.onInterceptTouchEvent()後返回true,則傳遞到onTouchEvent,當其返回true時,動作序列的後續事件不會再通過onInterceptTouchEvent了,而是在dispatchTouchEvent中直接傳遞於onTouchEvent。注意:此處點擊MylinerLayout和MytestView效果一致。
例子2:
類 |
方法 |
返回值 |
說明 |
MyLinerLayout |
dispatchTouchEvent |
True |
調用super. dispatchTouchEvent |
onInterceptTouchEvent |
False |
False則點擊非子view(沒有子view處理)時會傳遞於onTouchEvent,但是如果點擊MyTestView,即它的子view,則會傳遞到子view的onDispatchTouchEvent |
|
onTouchEvent |
true |
True 則後續動作序列直接發到此處,不經過onInterceptTouchEvent |
|
MyTestView |
dispatchTouchEvent |
True |
調用super. dispatchTouchEvent |
onTouchEvent |
True |
|
圖1:點擊父view
說明:onInterceptTouchEvent返回false本應該傳給下個子view的dispatchTouchEvent,但是,點擊的是父view,因此不存在子view而直接傳給自己的onTouchEvent,並且onTouchevent返回true,所以,後續事件不經過onInterceptTouchEvent(確定了自己要處理就不必再考慮如何分發給子view了)
圖2:點擊子view
說明:可以看到雖然MytestView.onTouchEvent接受並返回了true,事件還是需要經過MyLinerLayout.onInterceptTouchEvent(這是一個通道,分發給子view就要經過),
總結:onInterceptTouchEvent要做的就是確定事件傳遞到哪個子view,如果返回false,但是又沒有子view處理(因爲根本就沒有點擊到子view),就自己處理了,而自己在onTouchEvent處理的後續事件就不必經過onInterceptTouchEvent了,它是判斷傳遞給子view的,都不是子view處理,就不用經過了。(以上說明,android事件處理機制中,明確誰要處理,確定後就會形成一條通道,後續事件就走這條通道吧)
注意:正常情況下dispatchTouchEvent會調用super. dispatchTouchEvent,並將其作爲返回值,其實這會傳遞下一個接受者,讓下個接受者處理並將最終的處理的返回值(在最後的onTouchEvent中,讓其決定是否還需要接受後續動作序列)作爲自己的返回值。而下個調用者即是onInterceptTouchEvent,不過它只是決定分發方向的,所以它的返回值對dispatchTouchEvent不影響,而onInterceptTouchEvent也可以調用super. onInterceptTouchEvent,但是這總返回false,即總希望讓子view來處理。一般不用
(2)onTouchEvent():
返回值 |
作用 |
True |
事件由自己處理消耗,後續動作序列讓其處理,因爲在down事件時確定了路徑,因此後續事件就不會迷路了 |
False |
自己不消耗事件了,向上返回讓其他來父view的onTouchEvent接受處理吧 |
例子3:
類 |
方法 |
返回值 |
說明 |
MyLinerLayout |
dispatchTouchEvent |
|
調用super. dispatchTouchEvent,根據不同的view的返回值會不同,不過此處總是返回false |
onInterceptTouchEvent |
False |
False則點擊非子view(沒有子view處理)時會傳遞於onTouchEvent,但是如果點擊MyTestView,即它的子view,則會傳遞到子view的onDispatchTouchEvent |
|
onTouchEvent |
False |
False 則後續動作序列一般不發到此處(要看dispatchTouchEvent的返回值,如果其使用super. dispatchTouchEvent,會使用本方法的返回值,即false)。 |
|
MyTestView |
dispatchTouchEvent |
|
調用super. dispatchTouchEvent,也會返回false |
onTouchEvent |
False |
|
圖1:點擊父view
說明:當傳遞到自己的onTouchEvent時,返回false,而dispatchTouchEvent也使用這返回值false,因此,本次操作的後續動作序列就不會再傳遞了,沒有view處理後續的move、up。除非再次點擊纔會有事件傳遞,不過,結果跟上圖一樣,處理了down返回false就沒下文了。
圖2:點擊子view
說明:當事件流向MytestView.onTouchEvent時,返回了false,說明自己不處理了,讓父view的onTouchEvent處理吧,而父view也返回false不處理,就繼續向上拋,直到消失,當down事件沒有被view確認處理,則後續動作序列也就不會再傳遞了。
例子4:跟例子3差不多,只是MyLinerLayout.onTouchEvent返回true
類 |
方法 |
返回值 |
說明 |
MyLinerLayout |
dispatchTouchEvent |
|
調用super. dispatchTouchEvent,根據不同的view的返回值會不同,不過此處總是返回false |
onInterceptTouchEvent |
False |
False則點擊非子view(沒有子view處理)時會傳遞於onTouchEvent,但是如果點擊MyTestView,即它的子view,則會傳遞到子view的onDispatchTouchEvent |
|
onTouchEvent |
True |
True 則後續動作序列直接發到此處,不經過onInterceptTouchEvent |
|
MyTestView |
dispatchTouchEvent |
|
調用super. dispatchTouchEvent,也會返回false |
onTouchEvent |
False |
事件沒有被消耗,傳給父view的onTouchEvent |
注意:這裏點擊父view會跟例子2中圖1一樣,因爲,事件根本沒有傳遞到子view的機會。
圖1:點擊子view
說明:當到達MyTestView. onTouchEvent時返回false,則傳遞給父view的onTouchEvent,而其返回true,說明就讓其處理吧,所以後續動作序列直接發到此處。
總結:onTouchEvent被認爲是動作的最終處理的函數,不管是父view還是子view處理,只要onTouchEvent消耗了事件(返回true),則認爲後續動作序列的通路已經確定,否則,向上處理,直到消失。
3、前面說的都是在view或viewgroup的重寫的處理事件的方法,但是,如果註冊了監聽器後事件又是如何走呢?