View的事件體系(二)


一.事件由activity開始傳遞,activity的dispatchTouchEvent代碼如下:

public boolean dispatchTouchEvent(MotionEvent ev){
if(ev.getAction() == MotionEvent.Action_Down){
onUserInteraction();
}
if(getWindow().superDispatchTouchEvent(ev){
return true;
}
return onTouchEvent(ev);
}
由於上面的代碼我們可以知道,會直接調用window的superDispatchTouchEvent方法,當該方法返回false的時候,纔會調用activity的onTouchEvent方法進行處理

window的實現類是PhoneWindow,實現方法如下:

public boolean superDispatchTouchEvent(MotionEvent event){
return mDecor.superDispatchTouchEvent(event);
}
由上代碼可知,直接調用了DecorView的superDispatchTouchEvent方法,點擊事件由此進入view體系進行分發。


二.在ViewGroup的dispatchTouchEvent方法中:

final boolean intercepted;
if(actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null){
final boolean disallowIntercept = ( mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if(!disallowIntercept){
intercepted = onInterceptTouchEvent(ev);
ev.setAction(action);
}else{
intercepted = false;
}
}else{
intercepted = true;
}

如果action_down事件由ViewGroup的子元素消耗,則mFirstTouchTarget != null

所以當mFirstTouchTarget == null時,表示ViewGroup的子元素不消耗action_down事件

這時action_move,action_up事件都會返回intercepted = true ,即該事件由ViewGroup處理


如果爲action_down事件或者mFirstTouchTarget!= null 時,

會判讀FLAG_DISALLOW_INTERCEPT標誌是否爲0,FLAG_DISALLOW_INTERCEPT由子view的requestDisallowInterTouchEvent方法設置,當設置爲true時才

intercepted = false,ViewGroup將無法攔截事件

但如果事件爲action_down,FLAG_DISALLOW_INTERCEPT會被重置,一定會調用onInterceptTouchEvent方法判斷是否進行攔截


三.交給view處理

如果intercepted = false,表示viewGroup不攔截事件,將交給子view進行處理

他會遍歷所有的子元素,

判斷子元素是否在播動畫已經點擊事件是否落在子元素裏,如果滿足該條件,那麼事件就傳給他處理。

他會調用子元素的dispatchTouchEvent方法,

如果子元素的dispatchTouchEvent返回true,那麼mFirstTouchTarget就會被賦值並終止對子view的遍歷。

newTouchTarget = addTouchTarget(child,idBitsToAssign);
alreadyDispatchedToNewTouchTarget = true;
break;
private TouchTarget addTouchTarget(View child,int pointerIdBits){
TouchTarget target = TouchTarget.obtain(child,pointerIdBits);
target.next = mFirstTouchTarget;
mFirstTouchTarget = target;
return target;

如果返回false,則會將事件分發給下一個子元素。


如果ViewGroup沒有 子元素,或者子元素處理了點擊事件但它的dispatchTouchEvent返回false

ViewGroup會自己處理點擊事件

if(mFirstTouchTarget == null){
handled = dispatchTransformedTouchEvent(ev,canceled,null,TouchTarget.ALL_POINTER_IDS);
}

四。View對點擊事件的處理

public boolean dispatchTouchEvent(MotionEvent event){
...
if(onFilterTouchEventForSecurity(event){
ListenterInfor li = mListenerInfo;
if(li != null && li.mOnTouchListener != null&&(mViewFlags & ENABLED_MASK)==ENABLED &&li.mOnTouchListener.onTouch(this,event){
result = true;
}
if(!result && onTouchEvent(event){
result = true;
}
}
...
return result;
}
}
如果設置了mOnTouchListener,就會調用onTouch方法

如果沒設置mOnTouchListener方法或者onTouch方法返回false纔會調用onTouchEvent方法

當View處於不可用狀態時,如果clickable或者long_clickable爲true,也會消耗點擊事件

if((viewFlags &ENABLED_MASK)==DISABLED){
 if(event.getAction()== MotionEvent.ACTION_UP &&(mPrivateFlags &PFLAG_PRESSED)!= 0){
setPressed(false);
}
return (((viewFlags & CLICKABLE) == CLICKABLE || (viewFlags & LONG_CLICKABLE) == LONE_CLICKABLE));
}
當發生ACTION_UP時會觸發performClick方法,如果View設置了OnClickListener,那麼performClick方法內部就會調用onClick方法



view的LONG_CLICKABLE屬性默認爲false,而CLICKABLE屬性默認則由具體的控件決定,如TextView爲false

setOnClickListener 或setOnLongClickListener方法會將相應的屬性設置爲true.




參考:Android開發藝術探索








三.交給view處理
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章