/**
- https://blog.csdn.net/caifengyao/article/details/65437695?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.edu_weight&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.edu_weight
- http://cache.baiducontent.com/c?m=mvBtrNWuT6MbBxyIL8-bLvI8F1CAmzvl_L1TBw2WalAHli8MrEIZIlGN9g_WLZ31DRgzaOZs2CkLSQDAFB15C5CqlO0uzorHN3eQqihiXmaFaF1FXBw9wegAnHWx_QHnpzA5RsxGHPghxXbPrNeOsMAygGTWk0WLbPw2LGKm8eqcgvRQ3Kz1tyGwTpI5ELZX&p=8179de5ece904ead08e2977e065295&newp=8679cd0495934eac58e6852d021483231610db2151d6d2146b82c825d7331b001c3bbfb423281a04d3cf7a6d03ad425ee8f73d75330923a3dda5c91d9fb4c5747999&s=c9f0f895fb98ab91&user=baidu&fm=sc&query=requestdisallowintercept++%CA%B9%D3%C3%B7%BD%CA%BD&qid=f1f9d2db0004ca4d&p1=3
*/
滑动冲突的两种解决套路
前面我们将滑动冲突分为了3种场景,并根据每一种场景提供了解决冲突的思路。但是这些思路解决的是判断条件问题,即什么情况下事件交给谁的问题。这一节将抛开前面的场景分类,介绍对所有场景适用的两种通用解决方法,
可以通俗地理解为处理滑动冲突的“套路”。这两种解决滑动冲突的方式为:外部拦截法和内部拦截法。
1、外部拦截法
顾名思义,就是在外部滑动控件中处理拦截逻辑。这需要外部控件重写父类的onInterceptTouchEvent方法,在其中判断什么时候需要拦截事件由自身处理,什么时候需要放行将事件传给内层控件处理,内部控件不需要做任何处理。
这个“套路”的伪代码表示所示:
复制代码
1 @Override
2 public boolean onInterceptTouchEvent(MotionEvent ev) {
3 boolean intercepted = false;
4 switch (ev.getAction()){
5 case MotionEvent.ACTION_DOWN:
6 intercepted = false;
7 break;
8 case MotionEvent.ACTION_MOVE:
9 if(父容器需要自己处理改事件){
10 intercepted = true;
11 }else {
12 intercepted = false;
13 }
14 break;
15 case MotionEvent.ACTION_UP:
16 intercepted = false;
17 break;
18 default:
19 break;
20 }
21 return intercepted;
22 }
复制代码
前面对滑动处理的场景分类,并对不同场景给了分析思路,它们的作用就是在这里的第9行来做判断条件的。所以,不论什么场景,都可以在这个套路的基础上,修改判断是否拦截事件的条件语句即可。另外,需要说明一下的是,第6行和第16行,
这里都赋值为false,因为ACTION_DOWN如果被拦截了,该动作序列的其它事件就都无法传递到子View中了,ListView也就永远不能滑动了;而ACTION_UP如果被拦截,那子View就无法被点击了,这两点我们前面的文章都讲过,这里再强调一下。
2、内部拦截法
顾名思义,就是将事件是否需要拦截的逻辑,放到内层控件中来处理。这种方式需要结合requestDisllowInterceptTouchEvent(boolean),在内层控件的重写方法dispatchTouchEvent中,根据逻辑来决定外层控件何时需要拦截事件,
何时需要放行。伪代码如下:
复制代码
1 @Override
2 public boolean dispatchTouchEvent(MotionEvent ev) {
3 switch (ev.getAction()){
4 case MotionEvent.ACTION_DOWN:
5 getParent().requestDisallowInterceptTouchEvent(true);
6 break;
7 case MotionEvent.ACTION_MOVE:
8 if (父容器需要处理改事件) {
9 //允许外层控件拦截事件
10 getParent().requestDisallowInterceptTouchEvent(false);
11 } else {
12 //需要内部控件处理该事件,不允许上层viewGroup拦截
13 getParent().requestDisallowInterceptTouchEvent(true);
14 }
15 break;
16 case MotionEvent.ACTION_UP:
17 break;
18 default:
19 break;
20 }
21 return super.dispatchTouchEvent(ev);
22 }
复制代码
除此之外,还需要外层控件在onInterceptTouchEvent中做一点处理:
复制代码
1 @Override
2 public boolean onInterceptTouchEvent(MotionEvent ev) {
3 if (ev.getAction() == MotionEvent.ACTION_DOWN) {
4 return false;
5 } else {
6 return true;
7 }
8 }
复制代码
ACTION_DOWN事件仍然不能拦截,上一篇文章分析源码的时候讲过,ACTION_DOWN时会初始化一些状态和标志位等变量,requestDisllowInterceptTouchEvent(boolean)作用会失效。这里再顺便强调一下,不明白的可以去上一篇文章中阅读这部分内容。
这种方式比“外部拦截法”稍微复杂一些,所以一般推荐使用前者。同前者一样,这也是一个套路用法,无论是之前提到的何种场景,只要根据实际判断条件修改上述if语句即可。对于requestDisllowInterceptTouchEvent(boolean)的相关信息,在前面的文章中介绍过,这里不再赘述了。
修改 dispatchTouchEvent方法 来处理事件冲突
PagerIndicator把事件给拦截了 我修改了他的 dispatchTouchEvent方法 请求他爹和他祖宗不要拦截我的事件
根据事件分发机制 dispatchTouchEvent->interceptTouchEvent->onTouchEvent
具体参看
http://www.cnblogs.com/AceIsSunshineRain/p/5187118.html
TabPagerIndicator.java
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
// 请求父控件及祖宗控件不要拦截当前控件的时间
getParent().requestDisallowInterceptTouchEvent(true);
return super.dispatchTouchEvent(ev);