当前位置: 首页 > news >正文

Android滑动冲突解决方法

外部拦截法
点击事件都先经过父容器的拦截处理,如果父容器需要此事件就拦截,如果不需要此事件就不拦截。(比较符合点击事件的分发机制)

  • 重写父容器的onInterceptTouchEvent(),在内部做出相应的拦截即可
  • ACTION_DOWN----------这个事件必须返回false,不拦截(父容器一旦开始拦截,那么后续的时间都会交给它处理),如果拦截,就会导致子元素无法收到ACTION_UP事件,????
  • ACTION_MOVE-----------这个事件根据具体情况决定是否拦截
  • ACTION_UP ---------------必须返回false,因为ACTION_UP事件本身没有多大意义。如果父容器返回true,就会导致子元素无法接收到ACTION_UP事件,这个时候onClick事件就无法触发。
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;/*** 外部拦截法:父容器通过onInterceptTouchEvent()决定是否拦截事件*/
public class ExternalInterceptParent extends ViewGroup {private float mLastX;private float mLastY;public ExternalInterceptParent(Context context) {super(context);}public ExternalInterceptParent(Context context, AttributeSet attrs) {super(context, attrs);}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {// 简单布局,只放置一个子Viewif (getChildCount() > 0) {View child = getChildAt(0);child.layout(0, 0, getWidth(), getHeight());}}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {boolean intercepted = false;float x = ev.getX();float y = ev.getY();switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:// 按下事件不拦截,否则后续事件收不到intercepted = false;mLastX = x;mLastY = y;break;case MotionEvent.ACTION_MOVE:// 判断是否为水平滑动,如果是则拦截事件float dx = x - mLastX;float dy = y - mLastY;if (Math.abs(dx) > Math.abs(dy)) {intercepted = true; // 水平滑动,父容器处理} else {intercepted = false; // 垂直滑动,不拦截,子View处理}mLastX = x;mLastY = y;break;case MotionEvent.ACTION_UP:// 抬起事件不拦截,否则子View无法接收点击事件intercepted = false;break;}return intercepted;}@Overridepublic boolean onTouchEvent(MotionEvent event) {// 处理父容器的滑动逻辑float x = event.getX();float y = event.getY();switch (event.getAction()) {case MotionEvent.ACTION_MOVE:float dx = x - mLastX;// 处理水平滑动...mLastX = x;mLastY = y;break;}return true;}
}    
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.Button;/*** 子View不需要特殊处理事件*/
public class ChildButton extends Button {public ChildButton(Context context) {super(context);}public ChildButton(Context context, AttributeSet attrs) {super(context, attrs);}@Overridepublic boolean onTouchEvent(MotionEvent event) {// 处理点击事件switch (event.getAction()) {case MotionEvent.ACTION_UP:// 处理点击逻辑performClick();break;}return super.onTouchEvent(event);}
}    


内部拦截法
父容器不拦截任何事件,所有事件都传递给子元素,如果子元素需要此事件就直接消耗掉,否则就交给父容器处理。(与Android事件分发机制不一样)

  • 重写子元素的onTouchEvent()
  • 父元素不能拦截ACTION_DOWN----------这个事件必须返回false,不拦截(父容器一旦开始拦截,那么后续的时间都会交给它处理),如果拦截,就会导致子元素无法收到ACTION_UP事件
  • 父容器默认拦截ACTION_MOVE和ACTION_UP事件,这样只有当子元素调用了parent.requestDisallowTouchEvent(),父元素才能拦截所需的事件
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.Button;/*** 子View通过requestDisallowInterceptTouchEvent控制父容器是否拦截事件*/
public class ChildButtonInternal extends Button {private InternalInterceptParent parent;private float mLastX;private float mLastY;public ChildButtonInternal(Context context) {super(context);}public ChildButtonInternal(Context context, AttributeSet attrs) {super(context, attrs);}@Overrideprotected void onAttachedToWindow() {super.onAttachedToWindow();// 获取父容器引用if (getParent() instanceof InternalInterceptParent) {parent = (InternalInterceptParent) getParent();}}@Overridepublic boolean onTouchEvent(MotionEvent event) {float x = event.getX();float y = event.getY();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:// 按下时请求父容器不拦截事件if (parent != null) {parent.requestDisallowInterceptTouchEvent(true);}mLastX = x;mLastY = y;break;case MotionEvent.ACTION_MOVE:float dx = x - mLastX;float dy = y - mLastY;// 如果是垂直滑动,允许父容器拦截事件if (Math.abs(dy) > Math.abs(dx)) {if (parent != null) {parent.requestDisallowInterceptTouchEvent(false);}}mLastX = x;mLastY = y;break;case MotionEvent.ACTION_UP:// 处理点击逻辑performClick();break;}return super.onTouchEvent(event);}
}    
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.ViewGroup;/*** 内部拦截法:父容器默认不拦截除DOWN外的事件*/
public class InternalInterceptParent extends ViewGroup {public InternalInterceptParent(Context context) {super(context);}public InternalInterceptParent(Context context, AttributeSet attrs) {super(context, attrs);}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {// 简单布局,只放置一个子Viewif (getChildCount() > 0) {View child = getChildAt(0);child.layout(0, 0, getWidth(), getHeight());}}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {// 关键点:DOWN事件必须返回false,否则后续事件不会传递给子Viewif (ev.getAction() == MotionEvent.ACTION_DOWN) {return false;} else {// 其他事件根据子View的请求决定是否拦截return !disallowIntercept;}}private boolean disallowIntercept = false;@Overridepublic void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {this.disallowIntercept = disallowIntercept;super.requestDisallowInterceptTouchEvent(disallowIntercept);}@Overridepublic boolean onTouchEvent(MotionEvent event) {// 处理父容器的滑动逻辑return true;}
}    

两种方法的对比

  1. 外部拦截法:简单直观,父容器控制事件拦截逻辑,子 View 无需特殊处理。适用于大多数场景。
  2. 内部拦截法:灵活性高,子 View 可以根据自身需求动态控制父容器是否拦截事件,但需要父容器配合(DOWN 事件必须返回 false)。适用于复杂交互场景。

在实际开发中,推荐优先使用外部拦截法,因为实现简单且不容易出错。只有在外部拦截法无法满足需求时,才考虑使用内部拦截法。

http://www.xdnf.cn/news/594703.html

相关文章:

  • 西交交互增强与细节引导的具身导航!OIKG:基于观察图交互与关键细节融合框架下的视觉语言导航
  • unittest
  • GITLIbCICD流水线搭建
  • 【Java高阶面经:数据库篇】17、分库分表分页查询优化:告别慢查询与内存爆炸
  • 软件设计师“设计原则”真题考点分析——求三连
  • [Usaco2007 Dec]队列变换 题解
  • AUTOSAR图解==>AUTOSAR_SRS_PortDriver
  • 硅基计划2.0 学习总结 叁
  • CLIP中的被动学习
  • OpenAI宣布:核心API支持MCP,助力智能体开发
  • memcpy 函数的使用 (C语言)
  • 110kV/630mm2电缆5km的交流耐压试验兼顾110kVGIS开关用
  • 彩礼的异化:婚姻市场中的资本规训与性别政治批判
  • NV013NV024美光固态闪存NV028NV034
  • Tomcat多实例配置
  • 从零开始学习QT——第一步
  • vue组件渲染到iframe里面(同域名下),组件可以在同一项目下维护
  • VPC的作用
  • python调wfdb库读欧洲st-t数据库
  • 让办公更聪明:OA系统如何重塑企业协作模式
  • 第六部分:第五节 - 数据持久化 (基础):管理厨房的原材料库存
  • NACOS2.3.0开启鉴权登录
  • 基于深度学习的无线电调制识别系统
  • 数据库基础面试题(回答思路和面试建议)
  • 小林八股Java集合笔记(8k字概要版)
  • 【调优】Java 调优学习笔记之字符串
  • ollama接口数据返回格式化数据,商品标题,商品详情
  • 八、Linux进程和计划任务管理
  • 【Dify学习笔记】:dify通过ollama加载DeepSeek-R1-32B模型无法加载!终于解决了!!
  • C++ QT生成GIF,处理原始图像RGBA数据,窗口生成简单的动画