使用者的每次觸碰(onclick,onlongclick,onscroll,etc.)都是由一個action_down+n個action_move+1個action_up組成的,使用者觸碰必先有個action_down響應,使用者觸碰結束必然會有個action_up。(當然如果在途中被攔截,就可能不會有了!)那麼view是如何分發消息和攔截消息呢?
1.view及其子類都會有的兩個方法:
public boolean dispatchtouchevent(motionevent ev) 這個方法用來分發touchevent
public boolean ontouchevent(motionevent ev) 這個方法用來處理touchevent
2.特殊的view子類viewgroup則還有一個方法:
public boolean onintercepttouchevent(motionevent ev) 這個方法用來攔截touchevent
3.分發
dispatchtouchevent 收到觸碰,則向最外層的view傳遞消息,再向子層的view分發
4.攔截:
onintercepttouchevent 攔截傳回true表示要攔截消息,不要再向子view傳遞(這裡的子view不是繼承關系,而是包容關系)。傳回false則表示不攔截消息,可以繼續向下一層級的view傳遞消息,子view将可以dispatchtouchevent 收到觸碰消息再分發消息
5.消息處理:
ontouchevent 處理事件,攔截了消息,或者是最後一個收到消息的view調用此方法來處理事件,若傳回true,則表示正确接收并處理。若傳回false則表示沒有被處理,将向父view傳遞(這裡的父view不是繼承關系,而是包容關系)
參考文檔:
<a target="_blank" href="http://blog.csdn.net/liutao5757124/article/details/6097125">http://blog.csdn.net/liutao5757124/article/details/6097125</a>
首先,看android的官方文檔正解
onintercepttouchevent()與ontouchevent()的機制:
1. down事件首先會傳遞到onintercepttouchevent()方法
2. 如果該viewgroup的onintercepttouchevent()在接收到down事件處理完成之後return false,
那麼後續的move, up等事件将繼續會先傳遞給該viewgroup,之後才和down事件一樣傳遞給最
終的目标view的ontouchevent()處理
3. 如果該viewgroup的onintercepttouchevent()在接收到down事件處理完成之後return true,
那麼後續的move, up等事件将不再傳遞給onintercepttouchevent(),而是和down事件一樣
傳遞給該viewgroup的ontouchevent()處理,注意,目标view将接收不到任何事件。
4. 如果最終需要處理事件的view的ontouchevent()傳回了false,那麼該事件将被傳遞至其上一
層次的view的ontouchevent()處理
5. 如果最終需要處理事件的view 的ontouchevent()傳回了true,那麼後續事件将可以繼續傳遞
給該view的ontouchevent()處理
這是官方文檔的說法,要是自己沒親自去寫個程式觀察哈,基本上沒法了解,是以上程式先,然後分析:
布局檔案main.xml
<span style="font-size: small;"><?xml version="1.0" encoding="utf-8"?>
<com.hao.layoutview1 xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<com.hao.layoutview2
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent" android:gravity="center">
<com.hao.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.hao.layoutview2>
</com.hao.layoutview1>
</span>
第一層自定義布局layoutview1.java
<span style="font-size: small;">package com.hao;
import android.content.context;
import android.util.attributeset;
import android.util.log;
import android.view.motionevent;
import android.widget.linearlayout;
public class layoutview1 extends linearlayout {
private final string tag = "layoutview1";
public layoutview1(context context, attributeset attrs) {
super(context, attrs);
log.e(tag,tag);
}
@override
public boolean onintercepttouchevent(motionevent ev) {
int action = ev.getaction();
switch(action){
case motionevent.action_down:
log.e(tag,"onintercepttouchevent action:action_down");
// return true; 在這就攔截了,後面的就不會得到事件
break;
case motionevent.action_move:
log.e(tag,"onintercepttouchevent action:action_move");
break;
case motionevent.action_up:
log.e(tag,"onintercepttouchevent action:action_up");
case motionevent.action_cancel:
log.e(tag,"onintercepttouchevent action:action_cancel");
}
return false;
}
public boolean ontouchevent(motionevent ev) {
log.e(tag,"ontouchevent action:action_down");
case motionevent.action_move:
log.e(tag,"ontouchevent action:action_move");
log.e(tag,"ontouchevent action:action_up");
log.e(tag,"ontouchevent action:action_cancel");
return true;
// return false;
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);
protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
super.onmeasure(widthmeasurespec, heightmeasurespec);
}</span>
第二層布局layoutview2.java
public class layoutview2 extends linearlayout {
private final string tag = "layoutview2";
public layoutview2(context context, attributeset attrs) {
super(context, attrs);
log.e(tag,tag);
}
@override
public boolean onintercepttouchevent(motionevent ev) {
int action = ev.getaction();
switch(action){
case motionevent.action_down:
log.e(tag,"onintercepttouchevent action:action_down");
// return true;
break;
case motionevent.action_move:
log.e(tag,"onintercepttouchevent action:action_move");
case motionevent.action_up:
log.e(tag,"onintercepttouchevent action:action_up");
case motionevent.action_cancel:
log.e(tag,"onintercepttouchevent action:action_cancel");
}
return false;
public boolean ontouchevent(motionevent ev) {
log.e(tag,"ontouchevent action:action_down");
log.e(tag,"ontouchevent action:action_move");
log.e(tag,"ontouchevent action:action_up");
log.e(tag,"ontouchevent action:action_cancel");
// return true;
return false;
}
自定義mytextview.java
import android.view.view;
import android.widget.textview;
public class mytextview extends textview {
private final string tag = "mytextview";
public mytextview(context context, attributeset attrs) {
// return true;
public void onclick(view v) {
log.e(tag, "onclick");
public boolean onlongclick(view v) {
log.e(tag, "onlongclick");
其實代碼很簡單,就是自定義了view,在view裡面都重寫了intercepttouchevnet (),和ontouchevent(),然後測試其傳回值,對監聽的影響,關鍵是自己動手,逐個測試,并預測結果,等你能預測結果的時候,也就懂了,需要修改的地方就是intercepttouchevnet 和ontouchevent的傳回值,他們決定了事件監聽的流程,下面我畫了一張圖,如有不足之處歡迎指正,謝謝!
下面是我的正解:
基本的規則是:
*1.down事件首先會傳遞到onintercepttouchevent()方法
*
* 2.如果該viewgroup的onintercepttouchevent()在接收到down事件處理完成之後return false(不攔截),
* 那麼後續的move, up等事件将繼續會先傳遞給該viewgroup,之後才和down事件一樣傳遞給最終的目标view的ontouchevent()處理。
*
* 3.如果該viewgroup的onintercepttouchevent()在接收到down事件處理完成之後return true(攔截,那麼後面的move,up事件不需要在看因為已經攔截了, 我們直接拿去處理ontouchevent()就可以了),那麼後續的move, up等事件将不再傳遞給onintercepttouchevent(), 而是和down事件一樣傳遞給該viewgroup的ontouchevent()處理,注意,目标view将接收不到任何事件。
下面例子示範:
* 1:layoutview1(31375): onintercepttouchevent action:action_down
* 2:layoutview2(31375): onintercepttouchevent action:action_down
* 3:layoutview2(31375): ontouchevent action:action_down
* 4:layoutview1(31375): onintercepttouchevent action:action_move
* 5:layoutview2(31375): ontouchevent action:action_move
* 6:layoutview1(31375): onintercepttouchevent action:action_move
* 7:layoutview2(31375): ontouchevent action:action_move
* 8:layoutview1(31375): onintercepttouchevent action:action_up
* 9:layoutview2(31375): ontouchevent action:action_up
* 該設定為:
* onintercepttouchevent:layoutview1為false,layoutview2為true
* ontouchevent:layoutview2為true
* 故而事件在layoutview2(onintercepttouchevent:傳回true)時被攔截并處理,根據上面說法就是layoutview2後續的move,up操作都不在經過onintercepttouchevent,直接
* 交給ontouchevent處理,結果也的确如此。(見:layoutview2的3,5,7,9,第一次是onintercepttouchevent處理如1,以後交給ontouchevent)
* 而layoutview1都還是要經過onintercepttouchevent(見layoutview1的4,6,8)
* 4.如果最終需要處理事件的view的ontouchevent()傳回了false(沒能處理這個事件,不能丢在傳回來讓父繼續),
* 那麼該事件将被傳遞至其上一層次的view的ontouchevent()處理。
* **************************************************************************
* 感覺像是一個圈,然後一直在找一個能處理這個消息的人,如果找到了就結束,沒找到就循環,直到回到發出消息的那個人
* 注(對下面):沒有标注的down表示攔截事件onintercepttouchevent,标注了ontouchevent就是處理事件
* a.如果都沒處理(onintercepttouchevent傳回false):
a(down)-->b(down)-->c(ontouchevent down)-->b(ontouchevent down)-->a(ontouchevent down),沒有執行up事件,注意有move的話,在down和up之間,下面的都一樣。
*b. b處理(b的onintercepttouchevent傳回true):
a(down)-->b(down)-->b(ontouchevent)-->a(ontouchevent up)-->b(ontouchevent up)-->(over)
形象說明:如果父親不攔截消息就傳給兒子,如果兒子要這個消息就處理(down),結束,然後有父親1--父親2--兒子以此釋放消息(up)。 然是如果兒子對這個消息置之不理,那這個消息又傳回父親,由父親來處理即。
下面給出了5中情況(不攔截表示onintercepttouchevent傳回false):
* 11** 父親1(layoutview1不攔截false)---父親2(layoutview2不攔截false)--兒子(mytextview,ontouchevent return true)--結束
* 22** 父親1(layoutview1不攔截false)---父親2(layoutview2不攔截false)--兒子(mytextview,ontouchevent return false)--回傳給父親2(ontouchevent return true)--結束
* 33** 父親1(layoutview1不攔截false)---父親2(layoutview2不攔截false)--兒子(mytextview,ontouchevent return false)--回傳給父親2(ontouchevent return false)--父親1(ontouchevent return true)--結束(如果都沒處理不在執行up action)
* 44** 父親1(layoutview1攔截true)--父親1(ontouchevent return true)--結束 (down--down(ontouchevent)--up(ontouchevent))
* 55** 父親1(layoutview1攔截false)--父親2(layoutview2攔截true)--父親2(ontouchevent return false)--父親1(ontouchevent return true)--結束 (down1--down2--down(2 ontouchevent)--down(1 ontouchevent)--up(1 ontouchevent))(1:父親2,2:父親2)
* ***************************************************************************
* 5.如果最終需要處理事件的view 的ontouchevent()傳回了true,那麼後續事件将可以繼續傳遞給該view的ontouchevent()處理。
*/
下面給出一張處理的流程圖:
下附源代碼:
下載下傳次數: 40
<a target="_blank" href="http://hao3100590.iteye.com/blog/1267294#">檢視圖檔附件</a>