Android滑动冲突处理方法。你知道吗?

安卓基础知识之View篇(四):View 事件滑动冲突解决方案 安卓基础知识系列旨在简明扼要地提供面试或工作中常用的基础知识,让对安卓还不太熟悉的小伙伴更快地入门。同时自己在工作中,也没法完全记住所有的基础细节,写这样的系列文章,可以让自己形成一个更完备的知识体系,同时给自己日后留个知识参考。 开始的开始 有了对事件分发机制的理解之后,我们知道事件是从顶层ViewGroup一层一层往下分发的,常用的事件类型有,按下事件(down)、滑动事件(move)、抬起事件(up)、触摸事件(touch)等,在处理滑动事件中,我们经常会碰到滑动冲突的场景。考虑一种布局由Scro. 阅读详情

在 Android 开发中,滑动冲突总是我们一个无法避免的话题。而对于解决方案却是众说纷纭。比如 RecyclerView 嵌套 RecyclerView ,直接通过相关方法禁掉内部 RecyclerView 的滑动; ScrollView 嵌套 RecyclerView 直接把 ScrollView 替换为 NestedScrollView 等等。但我们今天要说的是在自定义 View 中遇到滑动冲突时,我们又应该如何处理呢?

当然,今天的话题需要 View 的事件分发机制做理论前提 。

简单介绍 View 的时间分发机制
当然,这里也可以简单地提一下,基本的流程就是下面的伪代码。

public boolean dispatchTouchEvent(MotionEvent ev) {
    boolean consume = false;
    if (onInterceptTouchEvent(ev)) {
        consume = onTouchEvent(ev);
    }else{
        consume = child.dispatchTouchEvent(ev);
    }
    return consume;
}

当一个 ViewGroup 接收到一个事件的时候,首先会调用 dispatchTouchEvent() 方法进行事件分发,如果 onInterceptTouchEvent() 返回 true ,则代表当前 View 会拦截事件,则直接回调 onTouchEvent() 方法进行事件处理。如果不拦截,则直接回调子 View 的 dispatchTouchEvent() 方法,如此反复,一直到最里面的子 View。

当一个点击事件产生后,它的传递过程遵循以下顺序: Activity => Window => View ,即事件总是先传递给 Activity , Activity 再传递给 Window ,最后 Window 再传递给顶层 DocorView ,然后遵循上面的方式一直在最里层 View 。

而处理事件则从最里层 View 不断回传给自己的外层 View ,如果一直没有 View 进行处理,则直接会回传到Activity 中。

onTouchEvent() 返回 true 代表自己要处理。

既然都提了这么一点,也就突然想给出一些结论,参考自 Android 开发艺术探索:

同一个事件序列是指从手指接触屏幕(ACTION_DOWN)的那一刻起,到手指离开屏幕(ACTION_UP)的那一刻结束,中间含不定数量的 ACTION_MOVE 事件。
某个 View 一旦决定拦截事件,那么这一个事件序列都只能由它处理,并且它的 onInterceptTouchEvent() 方法也不会再调用。换句话说,比如一个 ViewGroup 里面有数个子 View,一旦 ACTION_DOWN 事件从 Activity 传到这个 ViewGroup 被其拦截,则后续的 MOVE 和 UP 等事件也不会传递到里面的子 View 中。
如果一个 View 一旦开始处理事件,如果它不消耗 ACTION_DOWN 事件,即 onTouchEvent() 返回为 false,那么同一事件序列中的其他时间也不会再交给它处理,直接会调用其父 View 的 onTouchEvent() 。
如果 View 不消耗除 ACTION_DOWN 以外的其他事件,那么这个点击事件会消失,此时父元素的 onTouchEvent() 并不会被调用,并且当然 View 可以持续收到后续的事件,最终这些消失的点击事件会传递给 Activity 处理。

ViewGroup 默认不拦截事件,View 没有 onInterceptTouchEvent() 方法,一旦有事件传递给它,则直接会调用 onTouchEvent() ,并且起默认都会消耗掉事件。除非它是不可点击的(即 clickable 和 longClickable 均为 false )。View 的 longClickable 默认都为 false ,而 clickable 分情况,比如 Button 默认为 true , TextView 默认为 false 。

View 的 enable 属性不会影响 onTouchEvent() 的默认返回值,哪怕一个 View 是 disable 状态的,只要它的 clickable 或者 longClickable 有一个为 true ,那么它的 onTouchEvent() 就会返回 true 。
requestDisallowInterceptTouchEvent() 可以在子元素中干预父元素的事件分发过程, 但是无法干预 ACTION_DOWN 事件。

事件优先顺序: setOnTouchListener() => onTouchEvent() => onClickListener()
一不小心发现还是挺多的,当然这些都是结论,具体可以跟着 面试系列:讲讲 Android 的事件分发机制 进行源码流程探讨,你会发现上面的结论很容易得到。

处理自定义 View 中的滑动冲突
对于大多数 Android 开发来说,处理滑动冲突好像很难,但实战一下又发现,好像也挺简单,因为这个实际上是有套路可循的。基本就两种方案:外部拦截法 && 内部拦截法。

外部拦截法
所谓外部拦截法,顾名思义,就是直接在父容器中直接拦截掉我们的滑动事件,让其不能进入到子元素中,这似乎和我们 RecyclerView 嵌套 RecyclerView 时禁用内部 RecyclerView 滑动有那么一丝相似之处,就是内部不处理就完事儿了。但细细品来又完全不一样,这里的外部拦截法会让内部元素根本就收不到滑动事件。

这种方法明显非常适合我们上面讲的事件分发机制。我们在接收 ACTION_MOVE 事件的时候,直接通过使 onInterceptTouchEvent() 方法返回 true 来直接拦截掉事件就可以了,伪代码想必大家也知道了:

override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
    ev?.run { 
        if (action == MotionEvent.ACTION_MOVE && 父容器需要点击事件){
            return true
        }
    }
    return super.onInterceptTouchEvent(ev)
}

代码很简单,我们仅仅需要在事件 ACTION_MOVE 时去处理我们的逻辑就好了,当满足我们的逻辑的时候,就拦截掉 ACTION_MOVE 事件给自己处理。

至于为什么不去拦截 ACTION_DOWN 和 ACTION_UP ,想必大家也清楚了。上面说了,如果拦截了 ACTION_DOWN 事件,那后续的 ACTION_MOVE 、 ACTION_UP 等其它事件均不会在调用 onInterceptTouchEvent() 方法,会直接交给当前容器处理。而如果我们拦截掉 ACTION_UP 的话,肯定会导致子元素的点击事件无法被处理,因为大家肯定都知道一个点击事件从 ACTION_DOWN 开始,从 ACTION_UP 结束,二者缺一不可。

内部拦截法
内部拦截法相对外部拦截法会复杂一些,所以我们通常来说,都更加推荐用外部拦截法进行处理。不过,内部拦截法依然有着它非常重要的地位,具体情况有可能会遇到。

内部拦截法的话,需要 requestDisallowInterceptTouchEvent() 方法的支持,这个方法是干什么的呢?顾名思义,请求是否不允许拦截事件,其接收一个 boolean 参数,表示是否不允许拦截。

我们直接重写子元素的 dispatchTouchEvent() 方法,得到伪代码如下:

override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
    ev?.run { 
        when(action){
            MotionEvent.ACTION_DOWN -> parent.requestDisallowInterceptTouchEvent(true)
            MotionEvent.ACTION_MOVE ->{
                if(满足需要让外部容器拦截事件){
                    parent.requestDisallowInterceptTouchEvent(false)
                }
            }
        }
    }
    return super.dispatchTouchEvent(ev)
}

想必代码也是非常简单易懂的,我们给父容器的 requestDisallowInterceptTouchEvent() 传递的参数代表是否不允许其拦截事件,当参数为 true 的时候代表不允许拦截,为 false 的时候代表拦截。所以看起来和外部拦截法也就如出一辙了。

不过仅仅有这点修改还不够,我们通过前面的理论基础知道,当我们的父容器拦截掉 ACTION_DOWN 事件的时候,所有的事件都无法再传递到子元素中,自然也就不会调用上面我们写的 dispatchTouchEvent() 方法了。所以我们在内部拦截法的时候还需要重写父容器的 onInterceptTouchEvent() 方法。

override fun onInterceptTouchEvent(ev: MotionEvent?): Boolean {
    ev?.run { 
        if (action == MotionEvent.ACTION_DOWN){
            return false
        }
    }
    return super.onInterceptTouchEvent(ev)
}

至此,基本介绍了两种处理滑动冲突的解决方案,在自定义 View 的时候结合实际场景也就可以得心应手了。

Android View滑动冲突处理 一 概述 上一篇文章我们讲述了Android View事件分发机制。如果你对View的事件分发还不熟悉,建议先去看一下 一文读懂Android View事件分发机制 它是我们今天滑动冲突解决的理论基础! 如果你已经对View的事件分发机制了然于胸,那么我们就根据View的事件分发机制,来给大家详细聊一下滑动冲突! 二 滑动冲突的常见场景与处理思路 当我们内外两层View都可以滑动时候,就会产生滑动冲突! 常见的滑动冲突场景: 1.外层与内层滑动方向不一致,外层ViewGroup是可以横向滑动的,内层Vie 阅读详情

相关推荐

Android滑动冲突解决方案指南

本文还有配套的精品资源,点击获取 简介:在Android开发中,滑动冲突是一个常见问题,尤其是涉及ScrollView和ListView等组件时。本文深入探讨了滑动冲突的产生原因,并提供了多种解决方法,包括重写触摸事件处理、设置NestedScrolling属性、使用SwipeRefreshLayout、使用NestedScrollView、使用RecyclerView和自...

weixin_36444661的博客 1445

【Android】Android滑动冲突解决方案

整体框架还是和上面内部拦截法给出的一样,在ACTION_MOVE处理水平增量和竖直增量,水平滑动就交给父容器处理,父容器调用onTouchEvent处理。如果此时想要横向滑动,父容器拦截该事件,在onTouchEvent方法处理;方法源码,ViewPager主要关心横向界面的切换,如果当前意图是横向切换,就响应用户操作并拦截。左右滑动让父容器的View拦截点击事件来处理,上下滑动让内部的View拦截点击事件来处理。主要在这里,根据x,y滑动距离判断当前的意图,如果是要横向滑动就调用。

Patrick_yuxuan的博客 1465

从拆解图看懂空心杯电机:有刷 vs 无刷内部结构全解析(附DIY注意事项)

本文深入解析有刷与无刷空心杯电机的内部结构差异,通过高清拆解图展示关键部件工艺特点,并分享实用的维护技巧和检测方法。重点对比两种电机在效率、寿命和适用场景上的优劣,为DIY爱好者提供详细的注意事项和操作指南。

xgboost6farmer的博客 516

关于嵌套滚动机制的一点思索

最近在做折叠式标题栏效果的时候遇到这样一个问题,布局代码如下所示,截取了两个片段, 我们看到这个页面上有几个个可以滑动的控件,AppBarLayout,NestedScrollview不是什么自定义的控件,是谷歌官方推荐的材料设计语言的控件的一种,可以直接在布局里使用,对于RecyclerView大家肯定不陌生,一个展示列表的控件,他跟Listview有很多渊源,这里主要讨论的问题...

haibowen的博客 728

Tessent Atpg系列 第七章 Running ATPG Patterns -- 如何书写proc文件

本篇文章是记录Tessent scan ATPG系列 本文并非是对userguide的完全翻译,而是自己对userguide的理解,此外,有部分比较深入的内容可能需要后续实验验证。本系列并不对tessent scan做过多描述。 请勿随意转载: 优快云 博主: ciscomonkey一种是在使用tessent scan之后使用ATPG 另一种是使用第三方工具,如snps的DFTC之后使用tessent的ATPG。 这里我们仅仅介绍without tessent scan之后tessent ATPG:对于t

ciscomonkey的博客 7694

Ubuntu 20.04 LTS下5分钟搞定ONLYOFFICE协作空间社区版(Docker版保姆级教程)

本文提供了一份在Ubuntu 20.04 LTS系统上,通过Docker快速部署ONLYOFFICE协作空间社区版的保姆级教程。内容涵盖从系统准备、Docker环境搭建,到执行自动化安装脚本、完成Web初始化的全流程,并详细说明了部署后的安全配置、数据备份及基本运维要点,帮助用户高效构建私有、安全、可控的团队文档协作平台。

weixin_28826961的博客 261

Android实践之ScrollView中滑动冲突处理

在Android开发中,如果是一些简单的布局,都很容易搞定,但是一旦涉及到复杂的页面,特别是为了兼容小屏手机而使用了ScrollView以后,就会出现很多点击事件的冲突,最经典的就是ScrollView中嵌套了ListView。我想大部分刚开始接触Android的同学们都踩到过这个坑,这一篇文章就从最近做的一个项目讲起,然后在过程中提供一些解决冲突的思路。

王三的专栏 2万+

手把手教你用CCS v7.3调试TI DSP28377:从连接仿真器到看懂Flash里的秘密

本文详细介绍了使用CCS v7.3调试TI DSP28377的全过程,从连接仿真器到解析Flash启动机制。通过实战演示和关键配置要点,帮助工程师快速掌握DSP调试技巧,并深入探讨bootloader设计与在线升级的实现方法,提升开发效率。

weixin_29158413的博客 408

Android处理ViewPager滑动冲突

本文可解决外部ViewPager和内部ViewPager左右滑动的冲突事件。 外层内层ViewPager都是左右滑动,不做处理,Android分不清到底是谁滑动,所以会出现滑动冲突。 首先我们先上完成效果图 事件分发理解 那么该如何解决滑动冲突呢? 在此之前我们需要知道Android的事件分发机制。 在这里不追溯源码,只说结论,源码分析有时间在写。 事件分发由Activity->ViewG...

WormholeStack 4762

激光光束质量评估与光斑尺寸计算:从理论到MATLAB实践

本文详细解析激光光束质量评估与光斑尺寸计算的理论基础及MATLAB实践方法,重点介绍M²因子的测量与应用。通过高斯光束模型、CCD成像法和MATLAB算法实现,帮助读者掌握从理论到实践的完整流程,提升激光系统调试与评估能力。

weixin_29083373的博客 449

zemax显微镜设计

光学显微镜(Optical Microscope,简写OM)是利用光学原理,把人眼所不能分辨的微小物体放大成像,以供人们提取微细结构信息的。我这里是插入进来之后才反转,如果之前已经在目镜的单独文件夹反转过了就不用了。将目镜的焦距设定为25mm,通过缩放,然后将镜头调转过来。镜头数据中的曲率半径、物距像距都设置为变量。将镜头的焦距整体变为16.25mm。将孔径类型设置为按照光阑尺寸浮动。打开物镜的文件,选择插入镜头。由英国物理学家虎克制作。2、像空间孔径0.25。3、像面大小-0.9。

fendoudecheng的博客 8546

Android 滑动冲突的解决方法

一、常见的滑动冲突场景场景1——外部滑动方向和内部滑动方向不一致,如:ViewPager中有多个fragment,而fragment中有ListView,这时ViewPager可以左右滑动,而ListView可以上下滑动,这就造成了滑动冲突。注意:这只是举个例子说明一下场景1,事实上ViewPager内部已经处理了这种滑动冲突,在采用ViewPager时,我们无需关注这个问题。场景2——外部滑动方向

struggle323的专栏 3915

某联达OA任意用户登录漏洞复现

由于`/WebService/Lk6SyncService/DirectToOthers/GetSSOStamp.asm`j接口未作限制,导致可以通过该接口调用`admin`的`cookie`值,通过对`LoginCredence`和`LoginTimestamp`的参数修改,进而实现任意登录进去系统.

千寻的博客 1589

【Android】NestedScrollView的简单用法与滚动冲突、滑动冲突

是 Android Jetpack 中的组件,用于容纳能够垂直滚动的视图。当页面布局的内容超过屏幕高度时,可以通过滚动展示全部内容。同时,在滚动的过程中与子视图可以进行事件协作。

2301_79977698的博客 5903

基于Scrapy+Playwright的学术会议信息智能爬取系统实战

本文详细介绍如何使用Python构建一个高效的学术会议信息爬取系统,结合Scrapy框架和Playwright无头浏览器技术,实现对全球学术会议数据的自动化采集、清洗和存储。文章包含完整的技术方案设计、代码实现细节以及性能优化策略,可帮助读者快速掌握现代网络爬虫开发的核心技术。关键词:Python爬虫、Scrapy、Playwright、学术会议、数据采集、反爬对抗python复制下载。

2201_76125261的博客 710

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

Android滑动冲突解决方法

Android滑动冲突解决方法滑动冲突首先讲解一下什么是滑动冲突。当你需要在一个ScrollView中嵌套使用ListView或者RecyclerView的时候你会发现只有ScrollView能够滑动,而ListView或RecyclerView不能滑动,这个就违背了我们写这段代码的意愿。我们想要的结果是当我们滑动ListView的时候ListView滑动,滑动ListView以外的地方的时候Scr

Android开源技术交流 3704

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Android解决滑动冲突

Android进阶之解决滑动冲突

weixin_45927121的博客 3162

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

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

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

04. 滑动冲突处理

什么是滑动冲突?滑动冲突指的是:当父容器和子 View都可以响应滑动手势时,系统无法判断应该让哪一个控件处理滑动事件,导致滑动行为出现异常。掘金:https://juejin.im/user/499639464759898简书:http://www.jianshu.com/u/92a2412be53e邮箱:[934137388@qq.com]

qq_35829566的博客 1188

android 滑动冲突

在android开发中会经常遇到各种问题,比较常见之一就有滑动冲突问题,只要出现滑动冲突,demo或者项目就无法正常工作, 那么问题是滑动冲突时怎么产生的,我们又应该如何解决这个滑动冲突问题那,其实在界面中只要内外两层同时可以滑动,这个时候就会产生滑动冲突,我们如何解决这个问题呢?这是一个简单又复杂的问题,简单因为滑动冲突有固定的解决办法,下面就分析一下滑动冲突, 1.我们常见的滑动冲突场景 ...

wk_先森的博客 6802

安卓View—滑动冲突(三)

安卓View—滑动冲突 文章目录安卓View—滑动冲突一、前言二、常见的滑动冲突场景场景1场景2场景3三、滑动冲突的处理规则场景1处理规则:场景2处理规则:场景3处理规则:四、滑动冲突的解决方式1.外部拦截法2.内部拦截法 一、前言 滑动冲突在开发过程中遇到的情况还挺多的,我以前开发 码助 等项目的时候遇到过,当然在使用抖音的时候也遇到过(当场给学姐提交BUG,结果修复的还挺快),我以前解决滑动冲...

睡客的博客 642

Android 滑动冲突解决

当有滑动效果的多个View嵌套使用的时候,就有可能导致滑动冲突问题。其本质其实是,滑动事件分发出了问题,即我们希望一个滑动事件在某种状态下交由A View来处理,却交给了B View来处理。解决问题的方法,当然就是根据具体场景的特点,通过滑动轨迹或者业务状态,判断出各种情况下的滑动操作与目标View的对应关系,然后通过View的onInterceptTouchEvent()等方法将滑动事件在各个状态下分发给对应的目标View。

UrasakiNakajima的博客 2997

Android之解决RecyclerView与NestedScrollView的滑动冲突方法

道理是一样的,因为刷新组件消耗了事件,RecyclerView并没有收到事件,所以出现了这种情况。解决的方法就是在刷新组件消耗事件的方法中进行判断,如果RecyclerView还能进行滑动,那就不消耗这个事件,将事件分发给RecyclerView,否则就消耗这个事件,进行数据的加载。这个方法判断刷新组件中的子容器是什么类型,并根据类型调用不同的方法,我们添加一段判断子容器是NestedScrollView的语句,注意要写在判断ViewGroup类型的上面。测试结果:可行,滑动冲突解决,但是仍存在一些瑕疵。

ChenYiRan123456的博客 5938

Android开发之滑动冲突解决方法

Android开发之滑动冲突 View开发中一个深入的话题:滑动冲突。相信开发Android的人都会有这种体会:滑动冲突实在是太坑人了,本来从网上下载的demo运行得好好的,但是只要出现滑动冲突,demo就无法正常工作了。那么滑动冲突是如何产生的呢?其实在界面中只要内外两层同时可以滑动,这个时候就会产生滑动冲突。如何解决滑动冲突呢?这既是一件困难的事又是一件简单的事,说困难是因为许多初级开发者面对...

qq_41563374的博客 778

Android开发View滑动冲突处理

最近在重构一个老项目,遇到ScrollView嵌套WebView的场景,因为WebView加载的网页并不是自适应,所以导致在滑动网页的时候异常卡顿,很明显是滑动冲突了,解决的同时,顺便做一下记录吧。 冲突场景 滑动冲突场景可简单分为两种: 外部和内部的滑动方向不一致 外部和内部的滑动方向一致 示图如下: 其他情况的滑动冲突都是在这两种冲突的基础上延伸出来的,或者以上两种场景的嵌套,面对这种...

乂星人 811

Android嵌套滑动造成的滑动冲突原理分析

Horizontal RecycleView 是Vertical RecyclerView的一个子view, CoordinatorLayout 实现了AppBarLayout 和 RecyclerView的协调联动,在向上滑动RecyclerView的时候,会先滑动AppBarLayout,再滑动RecyclerView,问题场景是在点击Horizontal RecycleView,然后向上滑动时,造成了Vertical RecyclerView 滑动,而AppBarLayout 没有滑动。

qq_32035241的博客 1139

滑动冲突的两种解决方法

滑动冲突场景 Android中有许多控件支持用户进行拖拽,滑动等操作,比如SeekBar,ViewPager,ScrollView,RecyclerView等等。随着业务的展现的需求变化,UI越来越复杂,不可避免的就会出现嵌套的多个可滑动View的情况,比如ViewPager中套ViewPager,ScrollView中套ViewPager,ViewPager中套RecyclerView,还有一...

ZhangJiqun&191cm&85kg 2803
上一篇: 避免面试尴尬,你需要了解的20个架构师相关缩写
下一篇: 折叠屏来袭,Android的适配攻略
Android 进阶学习者
博客等级 码龄7年 13粉丝 13原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值