一看就懂viewgroup事件分发 view事件分发

1.三个关键方法

public boolean dispatchTouchEvent(MotionEvent ev)
View/ViewGroup处理事件分发的发起者,View/ViewGroup接收到触控事件最先调起的就是这个方法,然后在该方法中判断是否处理拦截或是将事件分发给子容器

public boolean onInterceptTouchEvent(MotionEvent ev)
ViewGroup专用,通过该方法可以达到控件事件的分发方向,一般可以在该方法中判断将事件给ViewGroup独吞或是它继续传递给子容器,是处理事件冲突的最佳地点

public boolean onTouchEvent(MotionEvent event)
触控事件的真正处理者,最后每个事件都会在这里被处理

2.事件传递规则

ViewGroup收到事件后调用dispatch,在dispatch中先检查是否要拦截,若拦截则ViewGroup吃掉事件,否则交给有处理能力的子容器处理。
MotionEvent ev;//down or move or up or others...
viewgroup.dispatchTouchEvent(ev);

public boolean dispatchTouchEvent(MotionEvent ev){
boolean isConsumed = false;
if(拦截了){ //拦截了, 那么调用viewgroup的onTouchEvent, onTouchEvent返回true, dispatchTouchEvent返回true
isCousumed = this.onTouchEvent(ev);
}else{
//未被viewgroup拦截, 调用view的dispatchTouchEvent, view返回true, 证明子view消费了这个事件.
isConsumed = childView.dispatchTouchEvent(ev);
}
return isConsumed;

2.1viewgroup ”拦截了” 拦截与不拦截如何判断
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); // restore action in case it was changed
} else {
intercepted = false;
}
} else {
// There are no touch targets and this action is not an initial down
// so this view group continues to intercept touches.
intercepted = true;
}
2.1.1 肯定要拦截的情况
!(actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null)
说明: 当前操作不是”按下”操作, 并且, 之前没有”子View”的dispatch在ACTION_DOWN返回true(没有子view消费过事件)

2.1.2 肯定不拦截的情况
(actionMasked == MotionEvent.ACTION_DOWN || mFirstTouchTarget != null) && (disallowIntercept == true)
说明:
(1)当前是”按下”操作
(2)之前在”按下”操作的时候, 有子view消费过事件
满足(1) 或 (2) 的任意一条, 并且 子view设置了, 当前viewgroup不允许拦截

2.1.3 需要根据onInterceptTouchEvent来判断是不是拦截
onInterceptTouchEvent的返回值
返回true: 表示父容器直接拦截了该系列事件,后续不会再传递给子View了
返回false: 表示父容器ViewGroup暂时不拦截事件,事件有机会传给子View处理

(1)当前是”按下”操作
(2)之前在”按下”操作的时候, 有子view消费过事件
满足(1) 或 (2) 的任意一条, 并且
子view没有设置: “当前viewgroup不允许拦截”, 换句话说, 子view允许包含他自己的viewfroup进行拦截

2.2 如果viewgroup不拦截事件, 那么哪些子view可以接收到事件
if (!canViewReceivePointerEvents(child)
|| !isTransformedTouchPointInView(x, y, child, null)) {
ev.setTargetAccessibilityFocus(false);
continue;
}
ViewGroup通过判断所有的子View是否可见是否在播放动画和是否在点击范围内来决定它是否能够有资格接受事件。只有满足条件的child才能够调用dispatch。


3.dispatch的返回值:

true: viewgroup自己或者某个子view消费了这个事件
false: 自己和子view都没有消费这个事件

(1)最后dispatch返回ViewGroup的是isConsumed

(2)若isConsume == true,
说明ViewGroup处理了这个点击事件(ViewGroup自身或者子View处理的),并且这个系列的点击事件会继续传到这个ViewGroup来处理;
(3)若isConsume == false(ACTION_DOWN时),
ViewGroup没办法处理这个点击事件,那么这个系类的点击事件就和该ViewGroup无缘了。会把这个事件上抛给自己的父容器或者Activity处理。
(4)任何View只要拒绝了一系列事件中的ACTION_DOWN(返回false),则后续事件都不会再传递过来了。
但如果拒绝了其他的事件,后续事件还是可以传过来的,比如View某次ACTION_MOVE没处理,这个没处理的事件最后会被Activity消耗掉(而不是View的父容器),但后续的事件还是会继续传给该View。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值