谈起Touch可以联想很多东西,比如OnTouchEvent触摸事件、事件分发机制、滑动冲突等等。本文旨在将这一方面相关的知识做一下梳理,丰富自己,丰富别人。Ready GO!
一、OnTouchEvent
1.基本坐标系以及XY值的区别
1)先了解一下Android的基本坐标系(看图)
2)View来获取相对位置
2.MotionEvent的详解
1)getAction()与getActionMasked()的区别
简单来讲:一个应用于单点触控比较多,一个应用于多点触控比较多(当然也可以单点触控)。
复杂来讲:当多个手指在屏幕上按下的时候,会产生大量的事件,一般来说我们可以通过为事件添加一个int类型的index属性来区分,或者让二者结合在一起,毕竟一个变量更简洁一点。
int类型共32位(0x00000000),他们用最低8位(0x000000ff)表示事件类型,再往前的8位(0x0000ff00)表示事件编号。
*注:1、多点触控时必须使用getActionMasked()来获取事件类型。
2、单点触控时由于事件数值不变,使用getAction()和getActionMasked()两个方法都可以。
3、使用 getActionIndex() 可以获取到这个index数值。不过请注意,getActionIndex() 只在 down 和 up 时有效,
move 时是无效的。
2)单点触控一般的coding方式
3)多指触控的coding方式
二、事件分发机制
先祭一张流程图,其实看图完全可以明白,不说废话,图在此 |||(当然层级是Activity -> ViewGroup -> View)
其实想想也是语气写一堆Demo来验证这个问题 既繁琐也易忘,不如一张图片来的实在
以这个层级来看,事件传递的起点是Activity的dispatchTouchEvent 方法每个层级的dispathTouchEvent的方法 只有返回super才会正常向下传递,返回true都会被自己本方法消费,返回false都会抛给上层的onTouchEvent方法,由于activity为顶级,故也是抛出事件
OnTouchEvent方法只有返回true的时候才会自己做处理,返回false或者super都会抛给上层的OnTouchEvent方法只有ViewGroup才有onInceptTouchEvent方法,此方法也是事件拦截方法,多用于处理滑动冲突等等方面
mmp,好像能说的就是这些,说的不繁琐,简单点,说太多了我也不会 哈哈哈
三、滑动冲突
其实滑动冲突,现在都是基础,常备之课,也没啥难的简单说一说,简单记一记。
1.原因(说什么之前先说原因)
说到底,都是事件分发的锅(事件分发:mmp,这锅我不背),子View滑动的时候想要权限,老子又不给,子View又划不动,或者给了也没说好 给到哪里,滑动到边界的时候 模棱两可,用起来卡卡顿顿。滑动冲突出现在同方向滑动比较多。
2.举个栗子
同向的ScrollView和RecyclerView、同向ViewPager和RecyclerView (不过ViewPager内部已经做过处理,会检测子View的是否可以滑动)、很多很多吧
来个图吧,没个图不太好进行下去,不然有点乏味
第一种情况是最好解决的,可以通过touch时间处理,move的XY差值作比较,用初中的学到的Sin函数和tan(弹镇特)函数来解决
第二种情况其实也不难,还分外部(父View)解决和内部(子View)解决两种方法
其中外部解决就是 父View的OnInceptTouchEvent 方法,根据业务需求做相应的返回值 以此来拦截事件传递
内部解决就是 子View都是有这个方法 requestDisallowInceptTouchEvent(boolean) 汉译 请求不允许执行拦截 ,字如其意
3.解决问题
1)外部拦截法
即父View根据需要对事件进行拦截。逻辑处理放在父View的onInterceptTouchEvent方法中。我们只需要重写父View的onInterceptTouchEvent方法,并根据逻辑需要做相应的拦截即可。
根据业务逻辑需要,在ACTION_MOVE方法中进行判断,如果需要父View处理则返回true,否则返回false,事件分发给子View去处理。
ACTION_DOWN 一定返回false,不要拦截它,否则根据View事件分发机制,后续ACTION_MOVE 与 ACTION_UP事件都将默认交给父View去处理!
原则上ACTION_UP也需要返回false,如果返回true,并且滑动事件交给子View处理,那么子View将接收不到ACTION_UP事件,子View的onClick事件也无法触发。
而父View不一样,如果父View在ACTION_MOVE中开始拦截事件,那么后续ACTION_UP也将默认交给父View处理
2)内部拦截法
父View不拦截任何事件,所有事件都传递给子View,子View根据需要决定是自己消费事件还是给父View处理。这需要子View使用requestDisallowInterceptTouchEvent方法才能正常工作。
@子View Coding 风格
@父View Coding 风格
内部拦截法要求父View不能拦截ACTION_DOWN事件,由于ACTION_DOWN不受FLAG_DISALLOW_INTERCEPT标志位控制,一旦父容器拦截ACTION_DOWN那么所有的事件都不会传递给子View。
滑动策略的逻辑放在子View的dispatchTouchEvent方法的ACTION_MOVE中,如果父容器需要获取点击事件则调用 parent.requestDisallowInterceptTouchEvent(false)方法,让父容器去拦截事件。
自此,粗略的讲了onTouch方面的知识,就这样的,以后用过新的会在补充
good good study , day day up!
网友评论