Android View 的滑动冲突

标签: Android
3人阅读 评论(0) 收藏 举报

滑动冲突是如何产生的呢? 其实在界面中只要内外层同时可以滑动,这个时候就产生滑动冲突。

一、滑动冲突常见场景

常见的滑动冲突场景可以简单分为以下三种。

  • 场景1:外部滑动方向和内部滑动方向不一致; 外层的ViewGroup可以横向滑动,内层的View可以竖向滑动,如ViewPager内每个页面是ListView (ViewPager 已经处理了滑动冲突,所以在使用中并没有出现滑动冲突)
  • 场景2:外部滑动方向和内部滑动方向一致;外层的ViewGroup可以竖向滑动,内层的View也可以竖向滑动,如ScrollView 内部是ListView
  • 场景3:场景1和场景2 的嵌套

二、滑动冲突处理规则

场景一

    处理规则: 当用户左右滑动时,需要让外部的View拦截点击事件;当用户上下滑动时,需要让内部View拦截点击事件。

至于如何获得滑动方向,我们可以得到滑动过程中的两个点的坐标。一般情况下根据水平和竖直方向滑动的距离差就可以判断方向,当然也可以根据滑动路径形成的夹角、水平和竖直方向滑动速度差来判断。

场景二

由于外部与内部的滑动方向一致,那么不能根据滑动角度、距离差或者速度差来判断。这种情况下必需通过业务逻辑来进行判断。 比如业务上有规定: 当处于某种状态时需要外部View响应用户的滑动,而处于另外一种状态时则需要内部View来响应View的滑动,根据这种业务上的需求我们也能得出相应的处理规则。

场景三

它的滑动规则就更复杂了,无法根据滑动的角度、距离差以及速度差来判断,同样还是只能从业务上找突破点。

三、滑动冲突的解决方式

外部拦截法

外部拦截法是指 点击事件都先经过父容器的拦截处理,如果父容器需要此事件就拦截,如果不需要此事件就不拦截。 外部拦截法需要重写父容器的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: {
                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;
    }
  • 根据业务逻辑需要,在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处理。

内部拦截法

内部拦截法是指父容器不拦截任何事件,所有事件都传递给子元素,如果子元素需要此事件就直接消耗,否则,就交给父容器进行处理; 这种方法和Android 中的事件分发机制不一致, 需要配合requestDisallowInterceptTouchEvent 方法才能正常工作。下面是子View的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 deltaY = y - mLastY;
                if (父容器需要此类点击事件) {
                    parent.requestDisallowInterceptTouchEvent(false);
                }
                break;
            }
            case MotionEvent.ACTION_UP: {
                break;
            }
            default:
                break;
        }

        mLastX = x;
        mLastY = y;
        return super.dispatchTouchEvent(event);
    }

父View需要重写onInterceptTouchEvent方法,如下所示:

public boolean onInterceptTouchEvent(MotionEvent event) {

        int action = event.getAction();
        if (action == MotionEvent.ACTION_DOWN) {
            return false;
        } else {
            return true;
        }
    }
  • 内部拦截法要求父View不能拦截ACTION_DOWN事件,由于ACTION_DOWN不受FLAG_DISALLOW_INTERCEPT标志位控制,一旦父容器拦截ACTION_DOWN那么所有的事件都不会传递给子View。
  • 滑动策略的逻辑放在子View的dispatchTouchEvent方法的ACTION_MOVE中,如果父容器需要获取点击事件则调用 parent.requestDisallowInterceptTouchEvent(false)方法,让父容器去拦截事件。





查看评论

Android 仿饿了么加入购物车特效控件(自定义View实战)

利用 纯自定义View,实现的仿饿了么加入购物车控件,自带闪转腾挪动画的按钮。
  • 2017年01月22日 23:16

一文解决Android View滑动冲突

上一篇文章我们讲述了Android View事件分发机制。如果你对View的事件分发还不熟悉,建议先去看一下 一文读懂Android View事件分发机制 它是我们今天滑动冲突解决的理论基础! 如果...
  • u010302764
  • u010302764
  • 2017-05-27 09:57:06
  • 3252

一个Demo带你彻底掌握View的滑动冲突

本文已授权微信公众号:鸿洋(hongyangAndroid)在微信公众号平台原创首发。 最近在重新学习Android自定义View这一块的内容,遇到了平时开发中经常碰到的一个棘手问题:View的滑动冲...
  • tyk0910
  • tyk0910
  • 2016-11-30 22:40:36
  • 6577

Android 笔记 ViewPager的滑动与子view内部滑动事件的冲突问题

ViewPager 与子view的滑动冲突在上一次笔记中建设了一个可以滑动的photoView,显示图片,可以放大,滑动大部分时候这个自定义View会和ViewPager一起使用。也就是我们通常看到...
  • super_zq
  • super_zq
  • 2016-10-13 14:14:43
  • 1728

滑动冲突处理示例代码

  • 2016年07月24日 14:25
  • 563KB
  • 下载

Android中View的滑动冲突——Android开发艺术探索笔记

相信开发Android的人都会有这种体会:从网上下载的demo运行的好好的,但是只要出现了滑动冲突,Demo就无法正常工作了。但是不用担心,解决滑动冲突有固定的模式,常见的有内部拦截和外部拦截两种,只...
  • L664675249
  • L664675249
  • 2016-02-29 16:50:07
  • 2186

View的滑动冲突解决方案

1.常见的滑动冲突场景1.1 外部滑动方向和内部滑动的方向不一致这种情况我们经常遇见,比如使用viewpaper+listview时,在这种效果中,可以通过左右滑动切换页面,而每一个页面往往又是一个l...
  • u014316462
  • u014316462
  • 2016-07-24 16:09:08
  • 2076

通俗理解Android中View的事件分发机制及滑动冲突处理

说起Android滑动冲突,是个很常见的场景,比如SliddingMenu与ListView的嵌套,要解决滑动冲突,不得不提及到View的事件分发机制。 一、Touch事件传递规则分析 首先,我们要...
  • yyh352091626
  • yyh352091626
  • 2016-02-25 13:47:40
  • 12578

android 可滑动组件互相嵌套时滑动冲突解决方案总结

参考文章: http://www.jianshu.com/p/87a41b8c0dd0 http://www.jianshu.com/p/8bc0765dffc9   强烈推荐使...
  • scry5566
  • scry5566
  • 2016-08-24 11:52:38
  • 918

Android 从0开始自定义控件之 View 的滑动冲突详解(四)

> 转载请标明出处: [http://blog.csdn.net/airsaid/article/details/53244984](http://blog.csdn.net/airsaid/arti...
  • Airsaid
  • Airsaid
  • 2016-11-20 21:48:37
  • 3425
    个人资料
    持之以恒
    等级:
    访问量: 4107
    积分: 343
    排名: 23万+
    文章分类
    文章存档