【滑动冲突】常见情形及解决方案

安卓开发过程中滑动冲突的情形主要有2类:

  • 父view与子view的滑动方向不同,如:父view左右滑动,子view上下滑动或相反(ViewPage里面嵌套ListView)。这种情形是比较简单的,只需要根据不同的滑动动作进行相应的拦截与处理即可。
  • 父view与子view的滑动方向相同,即,父view左右,子view也左右(ViewPage里面嵌套可以缩放、移动的ImageView)。这种情形需要根据具体情况来进行拦截处理,比如父View在出现子View滑动到边缘的情况才进行拦截处理。

滑动冲突解决策略的理论基础为安卓的事件分发机制,针对滑动冲突的解决策略有以下两种:

  • 一种是外部拦截法:即当事件满足滑动条件,通过父View的【onInterceptTouchEvent】方法对其进行拦截,拦截之后将直接进入父View的onTouchEvent进行事件消费,不会再传入下级view。
  • 二种是内部拦截法:即通过子View的【dispatchTouchEvent】方法接收到down事件,然后获取父View的requestDisallowInterceptTouchEvent方法禁止其onInterceptTouchEvent拦截,当满足父View滑动条件的时候才允许。这种方法需要父View不拦截down事件,因为拦截了down事件后所有子元素的触摸事件都会失效。

建议采用第一种方法,易于理解,不容易出错。

ViewPager里面嵌套ListView

实际测试后发现:原生根本就不会产生滑动冲突!

1、左右滑动(ViewPager处理触摸事件)

  • 当ACTION_DOWN = 0,按下动作时,先是父ViewPager判断是否拦截,由于此时父ViewPager还不能判断是否要进行拦截,所以onInterceptTouchEvent返回false,即不拦截,所以ACTION_DOWN事件可以(必须、务必、一定)传到子ListView。
  • 当ACTION_MOVE = 2,移动动作时,在父ViewPager尚未识别出此手势是左右滑动item的动作之前(一般是根据滑动的速度和累计距离判断),onInterceptTouchEvent同样也返回false,即同样不拦截,所以最初的这些ACTION_MOVE事件同样也可以传到ListView。
  • 一旦父ViewPager识别出此手势是左右滑动item的动作(比如水平方向移动了足够长的距离)
    • 1、那么onInterceptTouchEvent将返回true(红色框位置),即开始拦截,所以之后的这些ACTION_MOVE事件将无法传到ListView;
    • 2、并且父ViewPager会在此时传给子View一个ACTION_CANCEL= 3的"取消动作",当子ListView收到此事件后便取消了之前对此手势的预处理;
    • 3、并且此后父ViewPager将不再调用onInterceptTouchEvent判断是否需要拦截(因为它认为此后的事件都是自己需要的)
  • 此后所有的ACTION_MOVE、ACTION_UP=1事件都交由父ViewPager的onTouchEvent处理了。

2、上下滑动(ListView处理触摸事件)



可以发现,父ViewPager的onInterceptTouchEvent始终返回false,即从不会拦截触摸事件,所以上下滑动时的事件完全由ListView处理(这是最原始的状态)。

PS:

  • 父ViewPager的onInterceptTouchEvent在事件分发过程中(即dispatchTouchEvent方法调用时)并非是每次都会被调用的,一旦父ViewPager识别出此手势是自己需要的或不是自己需要的,之后都将不会再调用onInterceptTouchEvent判断是否需要拦截。
  • 所以判断判断某个View是否拦截了手势,只需看其最后一次调用onInterceptTouchEvent时的返回值即可。
  • 并且,很容易理解,其最后一次调用之前调用onInterceptTouchEvent时的返回值肯定都是false。

ListView里面嵌套ViewPager

1、上下滑动(ListView处理触摸事件)



 情况和上面的一样

2、左右滑动(ViewPager处理触摸事件)

情况同样和上面一样

ScrollView里面嵌套ListView

1、当ScrollView的内容没有超出屏幕时(也即ScrollView不需要上下滑动),不会产生滑动冲突(也即内部的ListView能正常滑动),所有触摸事件都由ListView处理。

2、当ScrollView的内容超出屏幕时(也即ScrollView需要上下滑动),由于ListView也需要上下滑动,所以会产生滑动冲突(也即内部的ListView讲不能正常滑动),所有触摸事件都由ScrollView处理!

SV嵌套LV滑动冲突 之 外部拦截法

外部拦截法即:重写父容器的onInterceptTouchEvent方法,当自己需要的时候就拦截,否则不拦截。可以很容易理解,因为这和android自身的事件处理机制逻辑是一模一样的。

核心代码为:

@Override

public boolean onInterceptTouchEvent(MotionEvent ev) {

boolean intercepted = false;

switch (ev.getAction()) {

case MotionEvent.ACTION_DOWN://down事件肯定不能拦截,拦截了后面的就收不到了

intercepted = false;

break;

case MotionEvent.ACTION_MOVE:

if (true) intercepted = false;//如果确定拦截了,就去自己的onTouchEvent里处理拦截之后的操作即可

break;

case MotionEvent.ACTION_UP:

//up事件我们一般都是返回false的,一般父容器都不会拦截他, 因为up是事件的最后一步,这里返回true也没啥意义。

//唯一的意义就是,如果父元素把up拦截了,将导致子元素收不到up事件,那子元素就肯定没有onClick事件触发了,这里的小细节 要想明白

intercepted = false;

break;

default:

break;

}

return intercepted;

}

SV嵌套LV滑动冲突 之 内部拦截法

内部拦截法即:父容器不做处理,在子View中调用getParent().requestDisallowInterceptTouchEvent(true),作用是:告诉父view,我的触摸事件由我自行处理,不要阻碍我

不过前提是:要保证父亲容器不能拦截down事件。



 核心代码为:

@Override

public boolean dispatchTouchEvent(MotionEvent event) {

switch (event.getAction()) {

case MotionEvent.ACTION_DOWN:

break;

case MotionEvent.ACTION_MOVE:

//这里指定在什么条件下,才会要求父View把触摸事件交给自己处理。注意这里是调用的【getParent().getParent()】

if (true) getParent().getParent().requestDisallowInterceptTouchEvent(true);//这句话的作用是告诉父view,我的触摸事件由我自行处理,不要阻碍我

break;

case MotionEvent.ACTION_UP:

getParent().getParent().requestDisallowInterceptTouchEvent(false);//个人感觉这行代码没啥用,因为父view本来就不会拦截

break;

}

return super.dispatchTouchEvent(event);

}

附件列表

时间: 2024-08-01 04:17:19

【滑动冲突】常见情形及解决方案的相关文章

view的滑动冲突解决方案

一.常见的滑动冲突场景 1.外部滑动方向和内部滑动方向不一致 2.外部滑动方向和内部滑动方向一致 3.上面两种情况的嵌套 二.滑动冲突处理的原则 场景1的处理原则是:当用户左右滑动时,需要让外部的view拦截点击事件,当用户上下滑动时,需要让内部的view拦截点击事件.场景2和场景3比较特殊,无法如同场景1一样原则的处理冲突,需要在业务上寻找突破点.比如业务上规定:当处于某种状态时需要外部View响应用户的滑动,而处于另一种状态时则需要内部View来响应View的滑动,根据这种业务上的需求我们也

android滑动冲突的解决方案

转载请注明出处: http://blog.csdn.net/a992036795/article/details/51735501 一.前言 Android 中解决滑动的方案有2种:外部拦截法 和内部拦截法. 滑动冲突也存在2种场景: 横竖滑动冲突.同向滑动冲突. 所以我就写了4个例子来学习如何解决滑动冲突的,这四个例子分别为: 外部拦截法解决横竖冲突.外部拦截法解决同向冲突.内部拦截法解决横竖冲突.内部拦截法解决同向冲突. 先上效果图: 二.实战 1.外部拦截法,解决横竖冲突 思路是,重写父控

解决TextView多行滑动与NestedScrollView等,滑动冲突,我的解决方案

1.首先要明白,什么时候回TextView处理滑动,什么时候不处理滑动 1.1往上滑动,到达文本底部就不要再处理了,如果往上滑动不在底部则继续TextView滑动 1.2往下滑动,到达文本顶部就不要再处理了,如果往下滑动不在顶部则继续TextView滑动 关键计算地方: 1.当前是上滑动还是下滑动(相对于屏幕) ,使用ev.getRawY()获得当前滑动位置在屏幕哪个地方 2.  计算文本客滑动到哪里即可停止, (行高*总文本行数)- (行高 * 最多显示行数)   int sum = getL

(转)ViewPager,ScrollView 嵌套ViewPager滑动冲突解决

ViewPager,ScrollView 嵌套ViewPager滑动冲突解决 本篇主要讲解一下几个问题 粗略地介绍一下View的事件分发机制 解决事件滑动冲突的思路及方法 ScrollView 里面嵌套ViewPager导致的滑动冲突 ViewPager里面嵌套ViewPager 导致的滑动冲突 轮播图的几种实现方式 先看一下效果图 ScrollView里面嵌套ViewPager ViewPager里面嵌套ViewPager View的 事件分发机制 这篇博客大打算详细讲解View的事件分发机制

关于Android滑动冲突的解决方法(二)

之前的一遍学习笔记主要就Android滑动冲突中,在不同方向的滑动所造成冲突进行了了解,这样的冲突非常easy理解,当然也非常easy解决.今天,就同方向的滑动所造成的冲突进行一下了解,这里就先以垂直方向的滑动冲突为背景,这也是日常开发中最常见的一种情况. 这里先看一张效果图 由于GIF 图片大小的限制.截图效果不是非常好 上图是在购物软件上常见的上拉查看图文详情,关于这中动画效果的实现.事实上实现总体的效果,办法是有非常多的,网上有非常多相关的样例,可是对某些细节的处理不是非常清晰.比方,下拉

windows蓝屏代码大全及常见蓝屏解决方案

对于以下的代码查询建议使用ctrl+F查询,而且很多蓝屏与黑屏的问题多是最近操作引起的,例如更新驱动,安装新的硬件.软件--把相关的配置调到最近的正常状况大多可以解决,确实不行时方可考虑重装系统,解决问题的大法,不过重装系统前请注意做好备份工作! 蓝屏代码含义 (代码已经做了省略,每个的x后面都少了4个0) 0 0x0000 作业完成.1 0x0001 不正确的函数.2 0x0002 系统找不到指定的档案.3 0x0003 系统找不到指定的路径.4 0x0004 系统无法开启档案.5 0x000

解决侧滑中ViewPager和SlidingMenu的滑动冲突

当我们在使用开源框架SlidingMenu时,如果要是使用到ViewPager,就会出现滑动冲突. 解决方案: }/** 解决ViewPager和侧滑冲突 */ public void changeSlidingMenuTOUCHMODE(int arg0) { switch (arg0) { case 0: if (getActivity() instanceof SlidingFragmentActivity) { SlidingFragmentActivity activity = (Sl

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

最近在重新学习Android自定义View这一块的内容,遇到了平时开发中经常碰到的一个棘手问题:View的滑动冲突.相信不少小伙伴都有相同的感觉,看似简单真正做起来却又不知道从何下手.今天就从一个简单的Demo带你彻底掌握解决View滑动冲突的办法. 老规矩,先上图: 示例图中是一个常见的下拉回弹,手指向下滑动的时候,整个布局会一起滑动.下拉到一定距离的时候松手,布局会自动回弹到开始的位置:手指向上滑动的时候,布局的子View会滑动到最底部,然后手指再向下滑动,布局的子View会滑动到最顶部,最

自定义控件(视图)2期笔记11:View的滑动冲突之 概述

1. 引入: 滑动冲突可以说是日常开发中比较常见的一类问题,也是比较让人头疼的一类问题,尤其是在使用第三方框架的时候,两个原本完美的控件,组合在一起之后,忽然发现整个世界都不好了. 那到底是为什么会产生滑动冲突呢 ? 答:其实在界面中只要存在内外两层同时可以滑动,这个时候就会产生滑动冲突. 2. 常见的滑动冲突的场景: 场景1:外部滑动方向和内部滑动方向不一致 场景2:外部滑动方法和内部滑动方向一致 场景3:上面两种的嵌套 场景1:主要是将ViewPager 和Fragment配合使用所组成的页