Android 之在View以及ViewGroup中Touch事件传递

来源:互联网 发布:数控机床数据采集 编辑:程序博客网 时间:2024/04/30 07:41

关于onTouch事件的系统学习,是参考:基于源码来了解Android的事件分发机制

个人总结:事件的分发还是基于View的视图树,进行递归遍历

①首先在ViewGroup中,先判断父控件(父View)是否进行拦截事件 onIntercept()。

②父View没有拦截,在dispatchTouchEvent中遍历子View的dispatchTouchEvent事件。

③在子View的dispatchTouchEvent事件中,判断当前子View是否注册了onTouchListener。

如果注册了,就执行onTouchEvent事件。

④如果当前子View没有注册onTouch事件,就回到父View的dispatchTouchEvent事件中,

遍历子View,知道遍历完成,没有子View去注册onTouchListener事件,就会调用

父View的super.dispatchTouchEvent()方法,来触发自己的监听器。

⑤子View注册了onTouchListener监听器,在ACTION_DOWN中,监听长按方法,通过一个Runnable对象,

来检测是当前子View是否注册了onLongClickListener监听事件。并设置一个boolean属性

mHasPerformLongPress = true。

⑥在当前注册了onTouchListener的ACTION_UP方法中,根据mHasPerformLongPress = fasle;时

检测当前子View是否注册了onClickListener监听。


执行顺序就是:

ViewGroup : onInterceptTouchEvent > ViewGroup : dispatchTouchEvent > View : dispatchTouchEvent

> View : onTouchEvent > View : onLongClick > View : onClick

如果遍历子View 没有注册onTouchListener,就调用:

ViewGroup : onInterceptTouchEvent > ViewGroup : dispatchTouchEvent > View : dispatchTouchEvent

ViewGroup :onTouchEvent > ViewGroup : onLongClick > ViewGroup : onClick


返回true,表示当前View消费了该事件,事件不再往下传递。

如果父View拦截消费了该事件,就会向子View传递一个ev.setAction(ACTION_CANCEL);

表示父View拦截消费了该事件,也是往子View传递的最后一个事件ACTION_CANCEL。


Tips:关于MotionEvent的几个API:

①ev.getX();//当前的X、Y坐标是基于父布局View的相对坐标值。即在父View左上角原点的(X,Y)坐标点。相对坐标

   ev.getY();


   ev.getRawX();//当前的X、Y坐标就是基于屏幕左上角原点的(X,Y)坐标点。绝对坐标。

   ev.getRawY();

②关于View上的ACTION_DOWN,ACTION_MOVE,ACTION_UP的一系列叫做事件流。

   如果当前View接收了父View视图的ACTION_DOWN,即在ACTION_DOWN中返回true,

   那么与ACTION_DOWN 相关的事件流都要分发给当前的子视图View。

   但是,父视图希望拦截其中的一些事件,不继续传递给子视图View,就需要给子视图

   传递一个ACTION_CANCEL事件。

关于多点触控的,pointer 的 

MotionEvent.ACTION_POINTER_DOWN:代表用户的第二根手机触碰屏幕

MotionEvent.ACTION_POINTER_UP:代表用户多点触控的第一个手指离开屏幕

每一个pointer都会有自己的id,index。

整个事件流中,pointer的id不会发生变化,但是index会发生变化。

int index = event.getActionIndex();

int mActivePointerId = event.getPointerId(index);

自己先对多点触控,留个坑,不是今天学习主线。国庆十月五号补全。立个flag。


0 0