您的位置:首页 > 移动开发 > Android开发

[Android] 解决 View 滑动冲突法则

2016-03-05 20:09 423 查看

前言

这是 demo 地址

上面 demo 用外部拦截法实现了滑动方向一致和不一致的两种冲突。

滑动冲突场景

场景 1————外部滑动方向和内部滑动方向不一致

场景 2————外部滑动方向和内部滑动方向一致

场景 3————上面两种情况的嵌套

场景 1,主要是 ViewPager 和 Fragment 配合使用组成的页面横向滑动效果,而 Fragment 里又包含了 ListView 竖直滑动的控件。由于 ViewPager 里做了滑动冲突的处理,所以使用 ViewPager 时没有出现滑动冲突的现象。

场景 2,内外两层都在同一个方向可以滑动。比如,使用 ViewPager 和 Fragment 配合做页面横向滑动。在 Fragment 中使用 RecyclerView 做横向滑动效果。

场景 3,是场景 1 和场景 2 的结合。比如,使用 ViewPager 和 Fragment 配合做页面横向滑动,Fragment 中使用 ListView 做竖直方向的滑动,而 ListView 中的 item 中包含横向滑动的 RecyclerView。这种场景有些复杂,但有时在实际工作也会遇到,比如我公司项目锋绘动漫的首页就是这种场景。

滑动冲突的解决方式

外部拦截法

外部拦截法是指触摸事件先经过父容器的拦截处理,如果父容器需要此事件就拦截,否则不拦截。外部拦截法需要重写父容器的 onInterceptTouchEvent 方法,在此方法中做相应的拦截即可,伪代码如下:

@Override public boolean onInterceptTouchEvent(MotionEvent ev) {

boolean intercept = false;
int x = (int) ev.getX();
int y = (int) ev.getY();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
intercept = false;
break;
case MotionEvent.ACTION_MOVE:
int dealtX = x - mInterceptX;
int dealtY = y - mInterceptY;
if(父容器需要当前事件){
intercept = true;
}else{
intercept = false;
}
break;
case MotionEvent.ACTION_UP:
intercept = false;
mInterceptX = mInterceptY = 0;

break;
}

return intercept;  }


在 onInterceTouchEvent 方法中,ACTION_DOWN 事件,父容器必须返回 false,因为一旦父容器拦截了 ACTION_DOWN,那么后续的 ACTION_MOVE 和 ACTION_UP 都会直接交由父容器处理,事件无法再传递给子元素。ACTION_UP 也必须返回 false,因为如果父容器 ACTION_UP 返回 true,就导致子元素无法接受 ACTION_UP,子元素中的 onClick 事件也就无法触发了。

内部拦截

内部拦截是指父容器不拦截任何事件,所有的事件都传递给子元素,如果子元素需要此事件就直接消耗掉,否则就交给父容器处理。这种方法和 Android 的事件分发机制不一致,需要配合 requestDisallowInterceTouchEvent 方法才能正常工作。我么需要重写子元素的 dispatchTouchEven 方法,伪代码如下:

@Override public boolean dispatchTouchEvent(MotionEvent ev) {
switch (ev.getAction()){
case MotionEvent.ACTION_DOWN:
getParent().requestDisallowInterceptTouchEvent(true);
break;
case MotionEvent.ACTION_MOVE:
if (父容器需要此事件){
getParent().requestDisallowInterceptTouchEvent(false);
}

break;
case MotionEvent.ACTION_UP:

break;
}
return super.dispatchTouchEvent(ev); }


上述代码是内部拦截的典型代码,当面对不同的互动策略时只需要修改里面的条件即可。除了子元素需要做处理父元素也要重写 onInterceptTouchEvent 方法,拦截除了 ACTION_DOWN 以外的其他事件,这样当子元素调用 getParent().requestDisallowInterceptTouchEvent(false) 时,父元素才能拦截所需要的事件。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 滑动冲突