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处理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值