Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android-點擊事件分發機制驗證

Android-點擊事件分發機制驗證

編輯:關於Android編程

簡介


點擊事件的事件分發,其實就是對MotionEvent事件的分發過程,即當一個MotionEvent產生之後,系統需要這個事件傳遞給一個具體的View,而這個傳遞過程就是分發過程。   點擊事件的分發過程由三個重要方法共同完成:
  • dispatchTouchEvent 事件分發
  • onInterceptTouchEvent 事件攔截
  • onTouchEvent 事件響應

方法介紹


public boolean dispatchTouchEvent(MotionEvent ev) 用來進行事件的分發,如果事件能夠傳遞給當前View,那麼此方法一定會被調用,返回結果受到當前View的onTouchEvent和下級View的方法的影響。
  • 如果return true,表示點擊事件被消耗掉。如果return false,表示點擊事件沒有被消耗   public boolean onInterceptTouchEvent(MotionEvent ev) 用來判斷是否攔截某個事件。
  • 如果return true,表示點擊事件被攔截,並將攔截到的事件交由當前 View 的 onTouchEvent 進行處理。如果return false,表示點擊事件未被攔截,View上的事件會被傳遞到子View上,由子View的dispatchTouchEvent來處理。
public boolean onTouchEvent(MotionEvent ev)
用來處理點擊事件,返回結果表示是否消耗當前事件。
  • 如果return true,表示點擊事件被接收並消費。如果return false,表示點擊事件未被消費。

三個方法之間的關系

publicbooleandispatchTouchEvent(MotionEventev){
booleanconsume=false;
if(onInterceptTouchEvent(ev)){
consume=onTouchEvent(ev);
}else{
if(hasChild()){
consume = child.dispatchTouchEvent(ev);
}else{
consume = onTouchEvent(ev);
}
}

returnconsume;
}

 

代碼實踐


界面UI布局

\

ParentLayout

後面例子,都是在此代碼的基礎上修改的
publicclassParentLayoutextendsLinearLayout{

publicParentLayout(Contextcontext){super(context);}

publicParentLayout(Contextcontext,AttributeSetattrs){super(context,attrs);}

publicParentLayout(Contextcontext,AttributeSetattrs,intdefStyle){super(context,attrs,defStyle);}

@Override
publicbooleandispatchTouchEvent(MotionEventev){
ABLog.e("DefaultReturn"+String.valueOf("default:false"));

returnsuper.dispatchTouchEvent(ev);
}

@Override
publicbooleanonInterceptTouchEvent(MotionEventev){
ABLog.e("DefaultReturn"+String.valueOf("default:false"));

returnsuper.onInterceptTouchEvent(ev);
}

@Override
publicbooleanonTouchEvent(MotionEventev){
ABLog.e("DefaultReturn"+String.valueOf("default:false"));

returnsuper.onTouchEvent(ev);
}
}

 

ChildView

後面例子,都是在此代碼的基礎上修改的
publicclassChildViewextendsTextView{

publicChildView(Contextcontext){super(context);}

publicChildView(Contextcontext,AttributeSetattrs){super(context,attrs);}

publicChildView(Contextcontext,AttributeSetattrs,intdefStyle){super(context,attrs,defStyle);}

@Override
publicbooleandispatchTouchEvent(MotionEventev){
ABLog.e("DefaultReturn"+String.valueOf("default:false"));

returnsuper.dispatchTouchEvent(ev);
}

@Override
publicbooleanonTouchEvent(MotionEventev){
ABLog.e("DefaultReturn"+String.valueOf("default:false"));

returnsuper.onTouchEvent(ev);
}
}

 

打印結果

點擊ChildView(1處),打印Log \ 點擊ParentView(2處),打印Log \

處理過程解釋

代碼實踐這種情況下,這三個方法,默認都發送false。對於三個方法return的介紹參考前面方法介紹。這裡,我們以點擊ChildView為例子,再次強調點擊實踐的分發流程:

\dispatchTouchEvent方法再探

事件分發-false

在ChildView代碼基礎上,將dispatchTouchEvent方法內容改為如下形式 publicclassChildViewextendsTextView{
...
@Override
publicbooleandispatchTouchEvent(MotionEventev){
ABLog.e("DefaultReturn"+String.valueOf("false"));
returnfalse; } 點擊ChildView(1處),打印Log \

事件分發-true

在ChildView代碼基礎上,將dispatchTouchEvent方法內容改為如下形式 publicclassChildViewextendsTextView{

@Override
publicbooleandispatchTouchEvent(MotionEventev){
ABLog.e("DefaultReturn"+String.valueOf("true"));
returntrue; } 點擊ChildView(1處),打印Log 觸發兩次Log打印?因為當ChildView的dispatchTouchEvent返回true時,這就表示一系列點擊事件都由ChildView處理,所以,兩次Log分別為手勢的Down和Up事件。而如果返回false時,這就表示一系列點擊事件不由ChildView處理,所以,只打印一次。 \

onTouchEvent方法再探

事件響應-false

在ChildView代碼基礎上,將onTouchEvent方法內容改為如下形式 publicclassChildViewextendsTextView{

@Override
publicbooleanonTouchEvent(MotionEventev){
ABLog.e("DefaultReturn"+String.valueOf("false"));
returnfalse;
} 點擊ChildView(1處),打印Log 和默認效果一樣,因為默認也是返回false。   \  

事件響應-true

在ChildView代碼基礎上,將onTouchEvent方法內容改為如下形式 publicclassChildViewextendsTextView{

@Override
publicbooleanonTouchEvent(MotionEventev){
ABLog.e("DefaultReturn"+String.valueOf("true"));
returntrue;
} 點擊ChildView(1處),打印Log 觸發兩次Log打印?原因同上,這一系列事件都有ChildView出發。 \

onInterceptTouchEvent方法再探

事件攔截-false

在ParentLayout代碼基礎上,將onInterceptTouchEvent方法內容改為如下形式 publicclassParentLayoutextendsLinearLayout{

@Override
publicbooleanonInterceptTouchEvent(MotionEventev){
ABLog.e("DefaultReturn"+String.valueOf("false"));
returnfalse; } 點擊ChildView(1處),打印Log   \   點擊ParentView(2處),打印Log \ 總結一下上面Log情況?Log結果都和一開始全部默認情況相同。onInterceptTouchEvent為false的情況,就是調用super.onInterceptTouchEvent的情況。onInterceptTouchEvent返回false,表示點擊事件不攔截,向子View傳遞。

事件攔截-true 事件響應-false

在ParentLayout代碼基礎上,將ParentLayout改為如下形式 publicclassParentLayoutextendsLinearLayout{

@Override
publicbooleandispatchTouchEvent(MotionEventev){
ABLog.e("DefaultReturn"+String.valueOf("default:false"));

returnsuper.dispatchTouchEvent(ev);
}

@Override
publicbooleanonInterceptTouchEvent(MotionEventev){
ABLog.e("DefaultReturn"+String.valueOf("true"));
returntrue;
}

@Override
publicbooleanonTouchEvent(MotionEventev){ ABLog.e("DefaultReturn"+String.valueOf("false")); returnfalse;
} } 點擊ChildView(1處)或者ParentLayout(2處),打印Log 為什麼點擊ChildView和ParentLayout顯示相同Log?因為MotionEvent一系列事件,已經被onInterceptTouchEvent攔截了,所以MotionEvent一系列事件將不會被傳遞到子View(ChildView)中。 為什麼攔截了點擊事件,但是Log只出現了一次?因為使用onInterceptTouchEvent攔截了點擊事件,只是攔截了點擊事件的傳遞,並沒有處理MotionEvent的一系列事件。更進一步說,只有dispatchTouchEvent方法返回true,才表示MotionEvent的一系列事件被處理。onTouchEvent方法返回true,只是間接的對dispatchTouchEvent產生了影響。 \

事件攔截-true 事件響應-true

在ParentLayout代碼基礎上,將ParentLayout改為如下形式 publicclassParentLayoutextendsLinearLayout{
@Override
publicbooleandispatchTouchEvent(MotionEventev){
ABLog.e("DefaultReturn"+String.valueOf("default:false"));

returnsuper.dispatchTouchEvent(ev);
}

@Override
publicbooleanonInterceptTouchEvent(MotionEventev){
ABLog.e("DefaultReturn"+String.valueOf("true"));
returntrue;
}

@Override
publicbooleanonTouchEvent(MotionEventev){
ABLog.e("DefaultReturn"+String.valueOf("true"));
returntrue;
} } 點擊ChildView(1處)或者ParentLayout(2處),打印Log 為什麼Log和之前看到的不一樣?對於這次的Log,其實還是包含了點擊事件Down和Up。在這我們用分割線分開,第一部分,出現了dispatchTouchEvent,onInterceptTouchEvent,onTouchEvent三個函數;第二部分,因為onInterceptTouchEvent(攔截方法),只被調用一次哦,所以只出現了dispatchTouchEvent, onTouchEvent兩個函數。 \

View中Listener的優先級


主要探究OnTouchListener和OnClickListener還有onTouchEvent三個方法之間的關系: \

界面

\

ChildView

publicclassChildViewextendsTextView{

publicChildView(Contextcontext){
super(context);
}

publicChildView(Contextcontext,AttributeSetattrs){
super(context,attrs);
}

publicChildView(Contextcontext,AttributeSetattrs,intdefStyle){super(context,attrs,defStyle);}

@Override
publicbooleanonTouchEvent(MotionEventev){
ABLog.e("DefaultReturn"+String.valueOf("false"));
returnsuper.onTouchEvent(ev);
}
}

 

MainActivity

publicclassMainActivityextendsAppCompatActivity{

@Override
protectedvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

ChildViewview=(ChildView)findViewById(R.id.myChildView);
view.setOnClickListener(newView.OnClickListener(){
@Override
publicvoidonClick(Viewv){
ABLog.e("OnClickListener");
}
});

view.setOnTouchListener(newView.OnTouchListener(){
@Override
publicbooleanonTouch(Viewv,MotionEventevent){
ABLog.e("setOnTouchListener");
returnfalse;
}
});
}
}

 

點擊ChildView(1處),打印Log 前一部分,為Action_Down觸發;後一部分,為Action_Up觸發。 \  

onTouch方法再探

將onTouch方法返回值改為true,表示處理點擊時間的一系列事件,將setOnTouchListener方法改為:
view.setOnTouchListener(newView.OnTouchListener(){
@Override
publicbooleanonTouch(Viewv,MotionEventevent){
ABLog.e("setOnTouchListener");
return true;
}
});

 

點擊ChildView(1處),打印Log 點擊時間在OnTouch方法中被處理,所以不會傳到onTouchEvent方法中去了。因此更加不會傳到OnClickListener監聽方法中去了。 一個為Action_Down觸發,一個為Action_Up觸發。 \    
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved