View的滑动冲突和解决方案
1.滑动冲突原因:
当有内外两层View同时可以滑动的时候,这个时候就会产生滑动冲突。
2.常见的冲突场景:
场景1:

场景2:

场景3:

4.解决方法种类:
(1)外部拦截法:

针对场景1,我们可以发现外部和内部的滑动方向不一样也就是说只要判断当前dy和dx的大小,如果dy>dx,那么当前就是竖直滑动,否则就是水平滑动。明确了这个我就就可以根据当前的手势开始拦截了。从view的事件分发中我们了解点击事件的分发顺序是 通过父布局分发,如果父布局没有拦截,即onInterceptTouchEvent返回false,才会传递给子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;
}
上面的代码差多就是外部拦截的通用模板了,在onInterceptTouchEvent方法中,
首先是ACTION_DOWN这个事件,父容器必须返回false,即不拦截事件,因为一旦父容器拦截了ACTION_DOWN这个事件,那么后续的ACTION_MOVE和ACTION_UP事件将直接交给父容器处理,这个时候事件没法继续传递给子元素了;
然后是ACTION_MOVE这个事件,这个事件可以根据需要决定是否拦截,如果父容器需要拦截就返回true,否则返回false;
最后是ACTION_UP这个事件,这里必须返回false,因为这个事件本身也没有太多意义。
so场景一的外部拦截解决方法:
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: {
int deltaX=x-mLastXIntercept;
int deltaY=y=mLastYIntercept;
if(Math.abs(deltaX)>Math.abs(deltaY)){
intercepted=true;
}else{
intercepted=false;
}
break;
}
case MotionEvent.ACTION_UP: {
intercepted = false;
break;
}
default:
break;
}
mLastXIntercept=x;
mLastYIntercept=y;
return intercepted;
}
场景二的外部拦截方法:
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: {
mLastYIntercept=y;
intercepted = super.onInterceptTouchEvent(event);
break;
}
case MotionEvent.ACTION_MOVE: {
if(listView.getFirstVisiblePosition()==0 &&y>mLastYIntercept){
intercepted=true;
}else if(listView.getLastVisiblePosition()==listView.getCount-1&&y <mLastYIntercept){
intercepted=false;
break;
}
intercepted = false;
break;
}
case MotionEvent.ACTION_UP: {
intercepted = false;
break;
}
default:
break;
}
mLastXIntercept=x;
mLastYIntercept=y;
return intercepted;
}
(2)内部拦截法
内部拦截法是指父容器不拦截任何事件,所有的事件都传递给子元素,如果子元素需要此事件就直接消耗掉,否则就交给父容器去处理
(android系统中,一次点击事件是从父view传递到子view中,每一层的view可以决定是否拦截并处理点击事件或者传递到下一层,如果子view不处理点击事件,则该事件会传递会父view,由父view去决定是否处理该点击事件。在子view可以通过设置此方法去告诉父view不要拦截并处理点击事件,父view应该接受这个请求直到此次点击事件结束)需要用到方法requestDisallowInterceptTouchEvent。
内部拦截通用模板:
public boolean onInterceptTouchEvent(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-mLastXIntercept;
int deltaY=y=mLastYIntercept;
if(父容器需要拦截的事件){
parent.requestDisallowInterceptTouchEvent(false); //父布局需要要拦截此事件
}
break;
}
case MotionEvent.ACTION_UP: {
intercepted = false;
break;
}
default:
break;
}
mLastXIntercept=x;
mLastYIntercept=y;
return super.dispathTouchEvent(event);
}
so 场景二的内部拦截解决方法:
//拦截除了Down事件以外的其他方法:
public boolean onInterceptTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
int action = event.getAction();
if(action == MotionEvent.ACTION_DOWN){
mLastXIntercept=x;
mLastYIntercept=y;
return super.dispathTouchEvent(event);
}else{
return true;
}
}
场景三建议使用内部拦截方法比较方便
View的滑动冲突和解决方案的更多相关文章
- 一个Demo带你彻底掌握View的滑动冲突
本文已授权微信公众号:鸿洋(hongyangAndroid)在微信公众号平台原创首发. 近期在又一次学习Android自己定义View这一块的内容.遇到了平时开发中常常碰到的一个棘手问题:View的滑 ...
- view的滑动冲突解决方案
一.常见的滑动冲突场景 1.外部滑动方向和内部滑动方向不一致 2.外部滑动方向和内部滑动方向一致 3.上面两种情况的嵌套 二.滑动冲突处理的原则 场景1的处理原则是:当用户左右滑动时,需要让外部的vi ...
- View的滑动冲突
一.常见的滑动冲突 场景1:外部滑动和内部滑动不一致 场景2:外部滑动和内部滑动一致 场景3:上面两种情况的嵌套 二.滑动冲突的处理方法 场景一:根据水平滑动还是竖直滑动判断到底由谁来拦截事件. 场景 ...
- 自定义控件(视图)2期笔记13:View的滑动冲突之 内部拦截法
1. 内部拦截法: 父容器不拦截事件,所有的事件全部都传递给子元素,如果子元素需要此事件就直接消耗掉,否则就交给父容器进行处理. 这种方法和Android中的事件分发机制不一样,需要配合request ...
- 自定义控件(视图)2期笔记12:View的滑动冲突之 外部拦截法
1. 外部拦截法: 点击事件通过父容器拦截处理,如果父容器需要就拦截,不需要就不拦截. 这种方法比较符合事件分发机制.外部拦截法需要重写父容器的onInterceptTouchEvent方法,在内部做 ...
- 自定义控件(视图)2期笔记11:View的滑动冲突之 概述
1. 引入: 滑动冲突可以说是日常开发中比较常见的一类问题,也是比较让人头疼的一类问题,尤其是在使用第三方框架的时候,两个原本完美的控件,组合在一起之后,忽然发现整个世界都不好了. 那到底是为什么会产 ...
- Android scrollview嵌套webview滑动冲突的解决方案
在Android开发中有时我们需要在scrollview中嵌套webview这时你会发现这两者的滑动事件产生了冲突导致:webview很难被滑动,即使被滑动了一点也非常不顺畅.解决方案也比较简单只需要 ...
- Android开发——View滑动冲突解决方案
0. 前言 我们在Android开发--事件分发机制详解中深入学习了事件分发机制,为我们解决Android开发中的滑动冲突问题做了初步准备.针对滑动冲突这里给出两种解决方案:外部拦截法和内部拦截法 ...
- (转载)Android滑动冲突的完美解决
Android滑动冲突的完美解决 作者:softwindy_brother 字体:[增加 减小] 类型:转载 时间:2017-01-24我要评论 这篇文章主要为大家详细介绍了Android滑动冲突的完 ...
随机推荐
- 洛谷P2371 [国家集训队]墨墨的等式
P2371 [国家集训队]墨墨的等式 题目描述 墨墨突然对等式很感兴趣,他正在研究a1x1+a2y2+-+anxn=Ba_1x_1+a_2y_2+-+a_nx_n=Ba1x1+a2y2+-+a ...
- golang 获取当前可执行程序的当前路径
import ( "errors" // "fmt" "os" "os/exec" "path/filepat ...
- PostgreSQL:COALESCE函数
COALESCE函数是返回参数中的第一个非null的值,它要求参数中至少有一个是非null的,如果参数都是null会报错. select COALESCE(null,null); //报错 selec ...
- HTML - 超链接标签相关
1. <!-- href : 要跳转的网页资源路径 title : 链接的标题, 鼠标移动到超链接上面会显示出来 target : 要跳转的网页资源的显示位置 _blank : 在新标签页中打开 ...
- csps模拟68d,e,f题解
题面:https://www.cnblogs.com/Juve/articles/11655531.html 三道数据结构? d: 贪心,先按a排序,然后枚举删了前i个a值比较小的,然后在剩下的里面删 ...
- 关于N个小球放M个盒子解答
以下是关于关于N个小球放M个盒子的几种情况的解答,蛮详细的(来自博友的) 求精:关于N个小球放M个盒子解答 - chensmiles的日志 - 网易博客http://chensmiles.blog. ...
- 19-10-31-B
%%%B哥 ZJ一下: 开题. 发现 语文考试???? 我不认识XD.老帅哥救我! 后来…… 对什么取模??? 什么玩意??输入什么?? 满足啥?? 全是亻 啊! 后来才知道是题楔×了 不管了. 然后 ...
- 容器安全与EDR的异同
以Docker为代表的容器技术,直接运行于宿主机操作系统内核,因此对于容器安全,很多人会有着这样的疑问:EDR(Endpoint Detection and Response)等主机安全方案,能否直接 ...
- 使用python和tableau对数据进行抓取及可视化
使用python和tableau对数据进行抓取及可视化 本篇文章介绍使用python抓取贷款及理财平台的数据,并将数据拼接和汇总.最终通过tableau进行可视化.与之前的python爬虫文章 不同之 ...
- 《DSP using MATLAB》Problem 7.37
代码: %% ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ %% Output In ...