解决Android 中那些嵌套滑动事件冲突问题--合集

Android嵌套滑动-Behavior方案实战及细节注意 笔者在2013年就收到Android嵌套滑动的UI效果需求,当时都是直接从监听滑动事件分发做起,至今再次收到这种类似的需求,一直以来想更新下之前的实现方式,相对于Behavior封装过的方案而言毕竟不够优雅,现就介绍前后两种方案。 老方案的思路 这种方式是底层,其他的封装(包括behavoir)都是基于此,直接重写父类(ViewGroup)的事件分发机制:dispatchTouchEvent... 阅读详情

这里写图片描述摘要: 本文主要讲的是Android滑动冲突事件的一些集锦,因为这是在日常开发中比较常见的一类问题,所以自己额外也从网上收集了一些博主们自己的理解,关于滑动事件,一些基本简单的布局都不会出现,也很容易搞定,但稍微复杂一些,比如一个页面里有纵横向RecyleView与纵向里有下拉刷新功能,这时就会造成横向不流畅,嵌套受阻。尤其是在借助三方开源框架的时候,两个原本完美的控件,组合在一起之后,忽然发现整个世界都不好了。(T▽T)

1. 双重方向RecyleView 嵌套类型

前提在纵向RecyleView里嵌套RecyleView时,如果纵向RecyleView 里还有下拉刷新的功能的时候,那么就会引起内部的横向RecyleView 的横向滑动体变差(而且只有纯横向滑动时,才能滑动内部的横向RecyleView ,否则滑动事件就会影响到下拉刷新)

解决方法思路:添加拦截判断,重写onIterceptTouchEvent()方法,通过记录下手指按下的位置,进行初始化标记,如果viewpager正在拖拽中,那么不去拦截它的事件,且实时获取当前手指的位置 .getX(),最后再利用初始末位置差进行判断,如果X轴大于Y轴位移,那么将事件交给viewPager处理,如果Y轴位移大于X轴,事件交给swipeRefreshLayout处理

public class MySwipeRefreshLayout extends SwipeRefreshLayout {

  private boolean mIsVpDragger;
  private final int mTouchSlop;
  private float startY;
  private float startX;

  public MySwipeRefreshLayout(Context context) {
    super(context);
    mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
  }

  public MySwipeRefreshLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
    mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
  }


  @Override
  public boolean onInterceptTouchEvent(MotionEvent ev) {
    int action = ev.getAction();
    switch (action) {
      case MotionEvent.ACTION_DOWN:
        // 记录手指按下的位置
        startY = ev.getY();
        startX = ev.getX();
        // 初始化标记
        mIsVpDragger = false;
        break;
      case MotionEvent.ACTION_MOVE:
        // 如果viewpager正在拖拽中,那么不拦截它的事件,直接return false;
        if (mIsVpDragger) {
          return false;
        }

        // 获取当前手指位置
        float endY = ev.getY();
        float endX = ev.getX();
        float distanceX = Math.abs(endX - startX);
        float distanceY = Math.abs(endY - startY);
        // 如果X轴位移大于Y轴位移,那么将事件交给viewPager处理。
        if (distanceX > mTouchSlop && distanceX > distanceY) {
          mIsVpDragger = true;
          return false;
        }
        break;
      case MotionEvent.ACTION_UP:
      case MotionEvent.ACTION_CANCEL:
        // 初始化标记
        mIsVpDragger = false;
        break;
    }
    // 如果是Y轴位移大于X轴,事件交给swipeRefreshLayout处理。
    return super.onInterceptTouchEvent(ev);
  }
}
2. 同方向滑动冲突

ScrollView嵌套ListView,或者双重ScrollView 嵌套。ScrollView相信大家都比较熟悉了,就是在展示一个页面的时候,当前屏幕不够时,可以左右移动查看屏幕外侧内容。

3. 不同方向滑动冲突

eg:ScrollView嵌套ViewPager ,或者是ViewPager嵌套ScrollView,这种在项目类型中是很常见的。目前对于模块嵌套较多的应用外层都是ViewPager+Fragment 的底部切换(如网易新闻,淘宝,京东)结构,这种时候如果处理不当,就会很容易出现滑动冲突。
但ViewPager里面嵌套ListView还是ScrollView都不会出现滑动冲突事件,毕竟是官方原生控件,都会考虑到,从而比较完善些。


滑动冲突解决思路
滑动冲突无疑就是在嵌套中有占一个主导地位的View,每次总是抢着帮外边一层View处理的滑动事件,这样就导致一种很别扭的用户体验,明明只是横向的滑动了一下,纵向的列表却在垂直方向发生了动作。就是说,这个占主导地位的View,每一次都身不由己的拦截了这个滑动的动作,因此,要解决滑动冲突,就是得明确告诉这个占主导地位的View,什么时候你该拦截,什么时候你不应该拦截,什么时候又应该轮到由下一层的View去处理这个滑动动作?从这些分析思路出发,从而就很好解决了。

这里不明白的同学,可以先看一下Android Touch事件的分发机制 的大致流程.

第二种滑动冲突,解决起来较为简单些,这里举个列子说明一下。
这里,说一下背景情况。之前做下拉刷新、上拉加载更多时一直使用的是PullToRefreshView这个控件,因为很方便,不用导入三方工程。在其内部可以放置ListView,GridView及ScrollView,非常方便,用起来可谓是屡试不爽。但是直到有一天,因项目需要,在ListView顶部加了一个轮播图控件BannerView。结果发现轮播图滑动的时候,和纵向的下拉刷新组件冲了。
如之前所说,解决滑动冲突的关键,就是明确告知接收到Touch的View,是否需要拦截此次事件。

解决方法:
解决方案1 ,从外部拦截机制考虑
相当是在PullToRefreshView 里嵌套了ViewPager ,那么每次优先接收到Touch事件的必然是PullToRefreshView.

在PullToRefreshView中:



 @Override
  public boolean onInterceptTouchEvent(MotionEvent e) {
    int y = (int) e.getRawY();
    int x = (int) e.getRawX();
    boolean resume = false;
    switch (e.getAction()) {
      case MotionEvent.ACTION_DOWN:
        // 发生down事件时,记录y坐标
        mLastMotionY = y;
        mLastMotionX = x;
        resume = false;
        break;
      case MotionEvent.ACTION_MOVE:
        // deltaY > 0 是向下运动,< 0是向上运动
        int deltaY = y - mLastMotionY;
        int deleaX = x - mLastMotionX;

        if (Math.abs(deleaX) > Math.abs(deltaY)) {
          resume = false;
        } else {
        //当前正处于滑动
          if (isRefreshViewScroll(deltaY)) {
            resume = true;
          }
        }
        break;
      case MotionEvent.ACTION_UP:
      case MotionEvent.ACTION_CANCEL:
        break;
    }
    return resume;
  }

这里最关键的代码就是这行

if (Math.abs(deleaX) > Math.abs(deltaY)) {
          resume = false;
        }

即在上面提及到的双重RecyleView嵌套里解决的前提横向滑动距离大于纵向时,无须拦截这次滑动事件( ̄▽ ̄)~* 嗯,其实就是这么简单,但前提是你必须理解Android Touch事件的传递机制,期间各个方法执行的顺序及其意义。

解决方案2,从内容逆向思维分析
有时候,我们不想去修改引入的第三方控件,或者说是无法修改时。就必须考虑从当前从Touch传递事件中最后的那个View逆向考虑。首先,由Android中View的Touch事件传递机制,我们知道Touch事件,首先必然由最外层View拦截,如果无法更改这个最外层View,那么是不是就没辙了呢?其实不然,Android这么高大上的系统必然考虑到了这个问题,好了废话不说,先看代码

 private BannerView carouselView;
  private Context mContext;

  private PullToRefreshView refreshView;

  .........

 refreshView.setOnTouchListener(new View.OnTouchListener() {
      @Override
      public boolean onTouch(View v, MotionEvent event) {
        carouselView.getParent().requestDisallowInterceptTouchEvent(false);
        return false;
      }
    });

    carouselView.setOnTouchListener(new View.OnTouchListener() {
      @Override
      public boolean onTouch(View v, MotionEvent event) {
        carouselView.getParent().requestDisallowInterceptTouchEvent(true);
        int x = (int) event.getRawX();
        int y = (int) event.getRawY();

        switch (event.getAction()) {
          case MotionEvent.ACTION_DOWN:
            lastX = x;
            lastY = y;
            break;
          case MotionEvent.ACTION_MOVE:
            int deltaY = y - lastY;
            int deltaX = x - lastX;
            if (Math.abs(deltaX) < Math.abs(deltaY)) {
              carouselView.getParent().requestDisallowInterceptTouchEvent(false);
            } else {
              carouselView.getParent().requestDisallowInterceptTouchEvent(true);
            }
          default:
            break;
        }
        return false;
      }
    });

说一下这个方法

public abstract void requestDisallowInterceptTouchEvent (boolean disallowIntercept)
子View如果不希望其父View拦截Touch事件时,可调用此方法。当disallowIntercept这个参数为true时,父View将不拦截。
好了,言归正传。这里拦截直接也很明确,在carouselView的onTouch方法中每次进入就设定父View不拦截此次事件,然后在MOTION_MOVE时候,根据滑动的距离判断再决定是父View是否有权利拦截Touch事件(即滑动行为)。

再者就是 让ViewPager 禁止滑动
或者我们干脆就把滑动给禁止了:

public class CustomViewPager extends ViewPager {

  private boolean isPagingEnabled = true;

  public CustomViewPager(Context context) {
    super(context);
  }

  public CustomViewPager(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  @Override
  public boolean onTouchEvent(MotionEvent event) {
    return this.isPagingEnabled && super.onTouchEvent(event);
  }

  @Override
  public boolean onInterceptTouchEvent(MotionEvent event) {
    return this.isPagingEnabled && super.onInterceptTouchEvent(event);
  }

  public void setPagingEnabled(boolean b) {
    this.isPagingEnabled = b;
  }}

后续……….

Android原生实现外层列表+内层横向网格,支持上下拉刷新与嵌套滑动协调 一个开箱即用的Android示例工程,用纯原生RecyclerView完成外层垂直列表、内层横向网格布局的嵌套结构。不依赖SmartRefreshLayout、BaseRecyclerViewAdapterHelper等第三方库,所有刷新逻辑通过CoordinatorLayout + SwipeRefreshLayout + 自定义NestedScrollView兼容方案实现,上拉加载由RecyclerView滚动监听触发,下拉刷新响应用户手势并重置状态。嵌套滑动冲突通过禁用内层RecyclerView的嵌 阅读详情

相关推荐

Android滑动冲突解决的例子

Android滑动冲突解决的例子

Android滑动冲突的场景及解决方案

滑动冲突常发生于两个可滑动的控件发生嵌套的情况下。比如RecyclerView嵌套ListView,RecyclerView嵌套ScrollView,ViewPager嵌套RecyclerView等。ViewPager之所以没有滑动冲突是因为它本身就已经帮我们解决掉了。但其它没帮我们处理的情况就需要我们自己写代码去处理。

xiaokangss的博客 2783

Android嵌套滑动冲突的解决方法

android在嵌套滑动的时候会产生滑动冲突。之前我也碰到,但是以前的笔记本丢失了,所以只能重新再写一章。 一.会产生滑动冲突的情况 那么什么时候会产生滑动冲突呢?比如你有个activity,activity的上半部分是一个布局,下半部分是一个可滑动控件(RecyclerView、ListView等),或者下半部分是个viewpager,里面的fragment布局是一个可滑动控件,这样的页面就会产生滑动冲突。 二.以前的做法 虽然我以前的笔记丢失了,但是当时的解决问题的思路我依然记得。 (1)重写一个viewpager继承系统的ViewPager,至于怎么重写的我不太记得了 (2)重写Re

使用Dialog时 让页面层使用了 JQ插件mCustomScrollbar滚动条固定

JQ插件mCustomScrollbar是让不同浏览器的滚动条样式能同一。 当有使用Dialog的时候页面内某些div区域内 使用到了滚动条 那么Dialog内使用到鼠标滚轮的时候就会和页面的滚动条冲突。 上图这种使用到了vue-cropper裁剪功能,当用户上传图片上来裁剪的时候,鼠标滚轮可以对图片进行缩放,但是页面层使用了mCustomScrollbar插件 会跟着滚动 体验很不好。 ...

Ace_with_Yu的博客 533

Qt制作大数据可视化大屏展示电子看板

Qt制作大数据可视化大屏展示电子看板 解决当前最火的大数据可视化大屏展示,整个项目通过Qt开发,集成了QML/QChart/ECharts及自定义控件等模块,所有的可视化控件都可以集成到其中。可以随意增加和减少模块,各个模块可以随意拖拽,整体可以个性化布局。模块标题栏可自定义,包括标题文本信息、文本颜色、宽度/高度、背景颜色、按钮个数等功能,满足各个样式需求。 实例中主要展示了现成的一些仪表盘...

Qt自定义控件及应用开发 7707

2025最新正版Autodesk 3ds Max 2022安装教程:从下载到中文环境配置全流程解析

Autodesk 3ds Max 2022是一款专业的三维建模、动画和渲染软件,广泛应用于影视制作、游戏开发、建筑可视化等领域。

waicsdn_haha的博客 1万+

解决ScrollView+RecyclerView的滑动冲突问题

两个滑动的布局放在一起使用难免会产生冲突,这时候就要把这个冲突给解决掉

bai981002的博客 2522

【达梦8】多实例监视集群的部署测试

确认监视器具有状态确认和自动接管两个功能。在数据守护系统的故障自动切换模式下,必须部署一个确认监视器,否则在出现数据库故障时,会导致数据库服务中断。DM 提供了两种确认监视器的配置形式,分别为单实例和多实例。但是当单实例确认监视器故障时,无法继续进行集群的故障自动接管和备库故障确认,影响正常使用,故提供了多实例确认监控器来进一步提高集群的高可用性。在多实例确认监视器中,只有一个实例作为确认监视器提供服务,其它实例作为备库存在而不提供服务。

weixin_45335507的博客 1675

Android View(三)——View的滑动冲突

文章目录一.滑动冲突的原因二.常见的冲突场景:三.滑动冲突的处理规则1.场景1的处理规则2.场景2的处理规则3.场景3的处理规则四.滑动冲突的解决方法1.外部拦截法1.1模板代码:1.2 实例代码:2.内部拦截法2.1模板代码:2.2实例代码:五.完整实例 一.滑动冲突的原因 在界面中当有内外两层View同时可以滑动的时候,这个时候就会产生滑动冲突。 二.常见的冲突场景: 场景1 场景2 场景3 三.滑动冲突的处理规则 1.场景1的处理规则 对于场景1的处理规则是,当用户左右滑动时,需

haazzz的博客 492

[uboot] (第一章)uboot流程——概述

[uboot] uboot流程系列: [project X] tiny210(s5pv210)上电启动流程(BL0-BL2)建议先看《[project X] tiny210(s5pv210)上电启动流程(BL0-BL2)》,根据例子了解一下上电之后的BL0\BL1\BL2阶段,以及各个阶段的运行位置,功能。==============================================

ooonebook的博客 1万+

在 Linux 64 位上遭遇 Signal 7 与 ST22 SYSTEM_CORE_DUMPED:从 es/implementation=std 到 /dev/shm 的一套落地排查法

摘要: Linux 64位SAP系统出现SYSTEM_CORE_DUMPED和Signal 7(对应SIGBUS)错误时,核心问题是进程因共享内存资源异常被操作系统强制终止。主要诱因包括:1)/dev/shm的tmpfs默认容量不足(通常仅占物理内存50%);2)SAP内存管理参数es/implementation=map在64位场景下的敏感性。解决方案应双管齐下:在实例profile设置es/implementation=std以降低对tmpfs的依赖,同时按(RAM+Swap)*75%重新配置/dev/

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 164

Android 解决滑动冲突

滑动冲突的处理规则 场景一:当用户上下滑动的时候,需要让外部的View拦截事件,当用户左右滑动的时候,需要让内部的View拦截事件。 场景二:通常需要内部View响应View的滑动。 解决方式 外部拦截法 内部拦截法

xiangxiongfly 1039

基于 51 单片机的智能手势控制小车设计与实现

智能手势控制小车以STC89C52RC 单片机为控制核心,通过手势识别模块采集用户手势指令,经单片机处理后驱动电机执行前进、后退、左转、右转等动作。该项目融合了传感器技术、单片机编程和电机驱动技术,具有成本低、易实现、互动性强的特点,适合作为嵌入式系统入门实践案例。本项目成功实现了基于 51 单片机的智能手势控制小车,通过 APDS-9960 模块采集手势信号,经单片机处理后驱动电机完成基本动作,验证了 “传感器 + 单片机 + 执行器” 的嵌入式系统设计思路。

weixin_42300449的博客 178

android开发问题合集

1. ViewPager中如果有页面要显示超出界面的部分,就是clipChildren = false,这时候设置了滑动效果,即 mViewPager.setPageTransformer(false, new ScaleTransformer(), ViewCompat.LAYER_TYPE_NONE);第三个参数要关掉硬件加速,要不然,滑动时,clipChildren = fal...

inwhites的博客 451

5ZCM6ZGrVDllSFLkv6Hmga/ljJbnrqHnkIbns7vnu58= GetFlowDropDown SQL注入

5ZCM6ZGrVDllSFLkv6Hmga/ljJbnrqHnkIbns7vnu58=、eHR/OA一体化智慧云平台、智慧一卡通云平台、行业软件开发与定制、智慧企业管理信息化咨询与项目服务为核心业务的顾问式管理咨询和软件个性定制开发的高科技股份集团公司。同鑫T9eHR信息华管理系统存在SQL注入漏洞,攻击者可通过该漏洞上传shell。关闭互联网暴露面或接口设置访问权限。利用sqlmap进行shell。

iSee857的博客 700

使用CUDA进行按流排序的内存分配的示例程序

在GPU编程中,按流排序的内存分配是一种常见的优化技术,它可以提高内存访问的效率。通过将内存分配与特定的CUDA流相关联,可以确保在GPU上的并发操作期间,内存分配操作与其他GPU计算操作同时进行,从而减少了潜在的内存访问延迟。请注意,上述示例中的代码仅供参考,并可能需要根据实际需求进行修改和调整。此外,为了完整性,我们省略了一些细节,例如主机指针的分配和释放,以及错误处理和错误检查等。在该示例中,我们创建了4个CUDA流,并使用内存池进行内存分配。然后,我们在每个流上执行了相应的内存访问操作,并使用。

Byte_O_O的博客 281

浅记Android开发中遇到的bug合集

不断试错的程序员!

Dream_fan的博客 2091

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

2024年Android最新抖音Android端“个人中心”页滑动冲突优化方案(1),2024年最新在线面试技巧

今天关于面试的分享就到这里,还是那句话,有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。最后在这里小编分享一份自己收录整理上述技术体系图相关的几十套腾讯、头条、阿里、美团等公司20年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。还有。

2301_79098336的博客 1246

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

Android滑动冲突的完美解决方案

一、Android滑动冲突的完美解决方案 在Android开发中滑动冲突可以说是比较常见的一类问题,也是比较让人头疼的一类问题,两个原本完美的控件,组合在一起之后,忽然发现整个世界都不好了。滑动冲突主要分为同方向滑动冲突和不同方向滑动冲突,下面本文将详细说明两种滑动冲突如何解决。 关于滑动冲突 在Android开发中,如果是一些简单的布局,都很容易搞定,但是一旦涉及到复杂

nicolelili1的专栏 1万+

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Android嵌套滑动冲突

android在嵌套滑动的时候会产生滑动冲突。之前我也碰到,但是以前的笔记本丢失了,所以只能重新再写一章。 一.会产生滑动冲突的情况 那么什么时候会产生滑动冲突呢?比如你有个activity,activity的上半部分是一个布局,下半部分是一个可滑动控件(RecyclerView、ListView等),或者下...

weixin_34238633的博客 284

Android滑动事件冲突案例及解决方案总结

前言 转载请声明,转自【https://www.cnblogs.com/andy-songwei/p/11072989.html】,谢谢! 前面两篇文章,花了很大篇幅讲解了Android的事件分发机制的原理性知识。然而,“纸上得来终觉浅,绝知此事要躬行”,前面讲的那些原理,也都是为解决实际问题而服务的。本文将结合实际工作中经常遇到的滑动冲突案例,总结滑动冲突的场景以...

我的专栏 2958

Android常见滑动冲突场景

Android中常见的滑动冲突主要分为三种:   1.外部滑动方向和内部滑动方向不一致   2.外部滑动方向和内部滑动方向一致   3.前两种的嵌套   既然滑动冲突都有既定的规律,那么解决滑动冲突也肯定有通用的方法.外部滑动方向和内部滑动方向不一致  在这种情形下,我们可以根据滑动距离(水平距离和垂直距离)来判断滑动方向,并且来决定是该由外部View来拦截还是由内部View来拦截,简单的来

lks1139230294的博客 1462

Android view嵌套滑动冲突的解决方案(一scrollview嵌套listview滑动冲突和高度不正常的问题)

近段时间,自己在做之前项目经验的一些总结,也刚好今天有个刚进入Android开发没多久的伙计问我塔项目中遇到的滑动冲突的问题,就是scrollView嵌套的listview。今天帮他解决问题的同时也记录下自己之前项目中遇到的冲突的解决方案。首先我们来看下滑动冲突的原因:借助任玉刚刚哥的《Android开发艺术探索》这本书,可以参考155到157页,同时也可以看下140页到154页的view的分发事...

smxueer的专栏 1247

《android ScrollView嵌套RecycleView滑动禁止》

场景 ScrollView嵌套多个RecycleView,导致垂直滑动的时候,ScrollView与RecycleView垂直滑动冲突问题。滑动时,造成屏幕卡顿的情况。 解决思路 禁止掉RecycleView的滑动功能 LinearLayoutManager layoutManager = new LinearLayoutManager(this) { @Override p...

墨客联盟 1973

android-----滑动冲突解决案例

之前的几篇博客,我测试了View事件分发机制中的一些知识点,我们理解事件分发机制的目的就是为了能够更好了知道View中事件的传递过程进而能够对于滑动冲突有针对性的解决措施,今天我们通过一个翻页实例来学习下滑动处理的方式之一-----外部拦截法;         因为要用到翻页,那么不可避免的要用到Scroller类,其实拿scrollBy和scrollTo也能做到翻页的效果,但不足是两者都是在瞬

扇扇来驰的博客 5716
上一篇: Android4种网络连接方式的比较
下一篇: Android7.0 较6.0的新特性比较--集全所有变更比较
Checkiming
博客等级 码龄10年 38粉丝 40原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值