你在Android中遇到过哪些滑动冲突?
对于滑动冲突,相信安卓开发的人都会有这种体会:本来从网上下载的demo运行得好好的,但是只要出现滑动冲突,demo就无法正常工作了。许多开发者面对滑动冲突都会显得束手无策,(包括小编)于是小编就赶紧到处学习方法,并整理了下面的滑动冲突类型及解决方法,希望对和小编一样的初学者有帮助。
常见的冲突场景
- 场景一:外部滑动方向和内部滑动方向不一致

外部滑动方向和内部滑动方向不一致
在主流应用中,几乎都会出现这种效果:首页可以通过左右滑动来切换页面,而每个页面内部往往又是一个ListView,这种情形下是有滑动冲突的(但是ViewPager内部处理了这种滑动冲突)
处理规则
—— 根据用户滑动的方向决定让内部View还是外部View拦截点击事件
- 场景二:外部滑动方向和内部滑动方向一致

外部滑动方向和内部滑动方向一致
在这类场景里,可以想象父View可以通过上下滑动切换页面,然而内部还是一个ListView,当用户滑动的时候系统不知道该将滑动事件分发给谁
处理规则
—— 根据业务的规定决定让内部View还是外部View拦截点击事件
比如说上述例子,可以采用内部拦截法,优先将滑动事件交给内部ListView处理,当ListView已经到达顶部或者底部已经无法再进行同方向的滑动时,就将滑动事件交回给外部View处理,实现换页功能。
- 场景三:上面两种情况的嵌套

多种情况的嵌套冲突
这类场景也很常见,假如你的首页是一个ViewPager,可以来回切换不同页面,每个页面中又有各自的ListView,然后其实还隐藏着一个SlidingMenu在左侧。
处理规则
—— 根据业务的规定决定让内部View还是外部View拦截点击事件
主要是最SlidingMenu的处理,业务上可以要求当用户的向右滑动是从app最左侧边缘开始时才将事件交给SlidingMenu处理。其他部分可以跟第一个场景一样。
常用解决方式
- 外部拦截法 —— 点击事件都先经过父容器的拦截处理,如果父容器需要此事件就拦截,如果不需要此事件就不拦截。
外部拦截需要重写父容器的onInterceptTouchEvent方法,伪代码如下:public boolean onInterceptTouchEvent(MotionEvent event){ boolean intercepted = false; int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()){ case MotionEvent.ACTION_DOWN:{ // 对于ACTION_DOWN这个事件,父容器必须返回false,因为父容 器一旦拦截了 // ACTION_DOWN,后续的ACTION_MOVE和ACTION_UP也都会直接交由父容器处理 intercepted = false; break; } case MotionEvent.ACTION_MOVE:{ if (父容器需要当前点击事件) { intercepted = true; } else { intercepted = false; } break; } case MotionEvent.ACTION_UP:{ intercepted = false; break; } default: break; } mLastXIntercept = x; mLastYIntercept = y; return intercepted; }
- 内部拦截法 —— 指父容器不拦截任何事件,所有的事件都传递给子元素,如果子元素需要此事件就直接消耗掉,否则就交由父容器进行处理。
内部拦截需要重写子元素的dispatchTouchEvent方法,伪代码如下:另外,父容器也要做如下修改:public boolean dispatchTouchEvent(MotionEvent event){ int x = (int) event.getX(); int y = (int) event.getY(); switch (event.getAction()){ case MotionEvent.ACTION_DOWN:{ parent.requestDisallowInterceptTouchEvent(true); break; } case MotionEvent.ACTION_MOVE:{ int deltaX = x - mLastX; int deltxY = y - mLastY; if (父容器需要当前点击事件) { parent.requestDisallowInterceptTouchEvent(false); } break; } case MotionEvent.ACTION_UP:{ break; } default: break; } mLastX = x; mLastY = y; return super.dispatchTouchEvent(event); }public boolean onInterceptTouchEvent(MotionEvent event){ int action = event.getAction(); if (action == MotionEvent.ACTION_DOWN) { return false; } else { return true; } }

浙公网安备 33010602011771号