Android滑动冲突解决方案

来源:互联网 发布:linux ip 编辑:程序博客网 时间:2024/05/13 10:39
在App中,可以滑动的控件随处可见(viewPager,listView),毕竟在移动设备上,屏幕就那么大,要想给用户呈现更多的内容,我们的view就得支持滑动了,多个可以滑动的View嵌套在一起,就会引发一个问题,那就是一个事件(MotionEvent)到来时,到底哪一个view响应呢?这时应用的选择困难症犯病了,它会变得抓狂,我们的应用就会失常,这时我们要做的就是帮助它做出选择。废话不多说,下面我们就分析一下不同场景下滑动冲突的解决方案(全是套路啊)。滑动冲突是View体系中一个深入的话题,理解滑动冲突的解决方法,需要对view的事件分发体制有一定的了解。
  • 滑动冲突场景

    滑动嘛,不是左右滑动,就是上下滑动,冲突场景无非就是这两种情况的组合,最常见的冲突场景主要有以下三种:(1)内外两层view滑动方向不同

    这种冲突场景也是最简单的一种了,在这里,外层view为水平方向的scrollView,内层view为listview。下面就用“外部拦截法”和“内部拦截法”分别对这种情景进行分析。① 外部拦截法:可想而知,这种方法是对外部view做处理,内部view不需做处理。由外部view来决定事件是否传递到内部view(当然,事件得能传递到外部view),如果外部view决定消耗此事件,则外部view进行事件拦截,反之,外部view不拦截事件,将事件传递到内部view进行处理。需要说一下,处理滑动冲突的策略并不是唯一的,只要可以解决问题即可,对于此种冲突场景,制定如下处理策略:我们可以计算滑动在x,y方向上的偏移量(当然也可以通过滑动角度),如果abs(dx)>abs(dy),说明用户左右滑动的趋势较为明显,外层view拦截并消耗事件,若abs(dx)<abs(dy),说明用户上下滑动的趋势较为明显,外层view不拦截事件,由内层view处理事件。我们需要实现外层view的InterceptTouchEvent(MotionEvent ev),来决定是否拦截事件。
    float latestX;    float latestY;    @Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        boolean isIntercept = false;        switch (ev.getAction()) {            case MotionEvent.ACTION_DOWN:                isIntercept = false;                break;            case MotionEvent.ACTION_MOVE:                float dx = Math.abs(ev.getRawX() - latestX);                float dy = Math.abs(ev.getRawY() - latestY);                if (dx > dy) {                    isIntercept = true;                } else {                    isIntercept = false;                }                break;            case MotionEvent.ACTION_UP:                isIntercept = false;                break;        }        latestX = ev.getRawX();        latestY = ev.getRawY();        return isIntercept;    }
       ② 内部拦截法:   外层view默认不拦截,由内层view决定事件是由自己消耗掉还是推给外层view处理,这种方法外层view和内层view都需要做处理。外层view需要实现onInterceptTouchEvent(MotionEvent ev),内层view需要实现dispatchTouchEvent(MotionEvent ev)。   外层view:
@Override    public boolean onInterceptTouchEvent(MotionEvent ev) {        boolean isIntercept = false;        if (ev.getAction() == MotionEvent.ACTION_DOWN) {            isIntercept = false;        } else {            isIntercept = true;        }        return isIntercept;    }
   内层view:
float latestX;    float latestY;    @Override    public boolean dispatchTouchEvent(MotionEvent ev) {        switch (ev.getAction()) {            case MotionEvent.ACTION_DOWN:                getParent().requestDisallowInterceptTouchEvent(true);                break;            case MotionEvent.ACTION_MOVE:                float dx = Math.abs(ev.getRawX() - latestX);                float dy = Math.abs(ev.getRawY() - latestY);                if (dx > dy) {                    getParent().requestDisallowInterceptTouchEvent(false);                }                break;            case MotionEvent.ACTION_UP:                break;            latestX = ev.getRawX();            latestY = ev.getRawY();            return super.dispatchTouchEvent(ev);        }
      (2)内外两层view滑动方向相同

处理这种冲突,就需要视业务需求而看了,我们的业务需求决定什么条件下让外层view消耗事件,什么条件下让内层view消耗事件,核心思想与上面的情景很类似,就是决定条件发生变化而已,这里就不重复了。

     (3)上面两种的组合

这种多重嵌套的情景就更复杂了,但是,归根结底,其处理思想与第一种相似,就需要看具体业务需求了。

1 0
原创粉丝点击