ViewDragHelper的点击事件处理
在上一篇ViewDragHelper的介绍后,已经完成了自定义控件SwipeLayout的滑动,这一篇,我们来处理它的点击事件。之前提到过,它有两个子view,最开始显示的是surfaceLayout,隐藏在右边的是bottomLayout。当你给surfaceLayout设置点击事件时,你会发现,surface确实可以点击,但向左滑动却什么反应都没有,还是在响应点击事件。原因是什么呢,通过对事件分发的认识,可以得出结论:由于给surfaceLayout设置了点击事件,导致这个子view的变成可点击的了,于是你手指的down事件从SwipeLayout向子view分发时,SwipeLayout并没有拦截这个down,而surfaceLayout作为ViewGroup,默认也不拦截,但是surface已经没有子view在给它分发了,它拦不拦截,这个down都得归它处理,由于surface设置了点击事件,所以它能消费了这个down事件。这么一来,SwipeLayout 如果不在拦截方法里做些处理,后面纷至而来的move事件,都会传递surface,那么SwipeLayout的onTouchEvent就怎么都不会调用,肯定也就滑不起来了。那为什么surface没设置点击事件时,swipeLayout可以滑动呢,这是因为surface不设置点击事件,那它就不会消耗down事件的,那么这个down事件会以冒泡的形式,再向swipeLayout传递,而swipeLayout的onTouchEvent始终返回true,所以swipe消耗了down,之后的move便会一直传递给它。
照这样看来,得down者,得move!但我们的点击事件是必须要设置的,这样就导致,surface一定会先于父view消耗这个down,好,down给surface没关系,但move事件父View表示我要抢过来。要不然因为你的点击导致我都滑不起来,我还有毛用。由于我们把SwipeLayout的拦截事件方法全部交给了viewDragHelper的shouldInterceptTouEvent ()这个方法,那么看看它什么情况下会拦截事件。

一顿switch判断后,最终会判断mDragState是不是等于拖动。那好说,我们就看这个变量在哪里被赋值。经过一番搜索,可以找到以下几个调用关系:

-------------------------------------------------------------------------------------------------------------------------------------------------------

------------------------------------------------------------------------------------------------------------------------------------------------------------------

--------------------------------------------------------------------------------------------------------------------------------------------------

从下往上看的话,你会发现在viewDragHelper的拦截方法中,当你一步步走完tryCaptureViewForDrag时,mDragState会被赋值等于STATE_DRAGGING。根据前面提过,子view是一定要消耗down的,接下来的move,从外往内传递,而且子view也没有设置不允许父view拦截的标志,那么父view的拦截方法就会一直调用,也就是shouldInterceptTouchEvent会一直调用。上面action =move是一直能进来的,那tryCaptureViewForDrag为啥不走呢,原因很明了了:就是前面的pastSlop一直等于false嘛!从pastSlop 的赋值情况来看,它的结果跟checkTouchSlop有直接的关系:接着看图:

在上一篇博客中,我们重写了mCallback的几个回调,但是并没有重写getViewHorizontalDragRange这个回调,看来有的回调不重写就会留坑。默认这个方法返回0,所以checkTouSlop也就返回false,pastSlope返回false,后面的方法不执行,move动作始终不被swipeLayout拦截,也就滑不起来。那我重写这个回调,让它返回值大于0,是不是就行了呢,当然可以!当checkHorzontal为true,系统会判断你手指从点击到滑动的这段距离是否超过系统认为的最小距离,如果超过,系统认为你是在滑动,那么后面发送是连锁反应导致swipeLayout拦截下move事和up事件,并在processTouchEvent里处理,这个方法根据不同的action调用callback,例如move会回调水平移动,以及位置改变,up会回调onViewReleased。下面是我重写的getViewHorizontalDragRange这个回调,
@Override
public int getViewHorizontalDragRange(@NonNull View child) {
return helper.getTouchSlop();
}
helper.getTouSlop的值就是上图中的mTouchSlop。这个值默认等于8,它还与动画的执行时间有关系,最好别设得太大。到这里,在运行下程序,surface的点击以及swipeLayout的滑动都可以了,但你滑着会发现还有一些问题,当swipelayout处于关闭状态,你向右滑会触发surface的点击事件,为什么呢,难道我右滑时,swipeLayout没有拦截成功这个move吗?当你这么猜想时,你可以在swipeLayout的拦截方法里打个日志,记录下
shouldInterceptTouchEvent的返回结果,你会发现,你的猜想就是对的!看来,有些回调你就算实现了,坑还是会有的。我们在分析下拦截里的move到了干了什么好事:

就上面的4个圈,给我们挖的坑,第一个圈里面,由于我们重写了上面的那个回调,现在它的返回值是true,没问题,第二个圈在前一篇博客里,记不记得我们在这个回调里设置了边界,当开始处于关闭状态,你向右滑,我们做了限制,让surface返回还是0.所以newLeft=0,第3个圈是刚重写的,它的值等于大于0,没问题,出问题的是,我们的newLeft = oldLeft,oldLeft是你点击view的左上角顶点的横坐标,它就是等于0的,所以,在这里直接break了。你看

圈里面提前break,跳出循环,导致tryCaptureViewForDrag 也不会执行,这样move、up事件还是会下发给surface的。这个问题怎么解决呢?其实很简单,你只要强制把返回结果改为true,后面的事交给processTouchEvent去搞定就完了。因为它就是负责将你的手势转为相应的回调去操作子view,拦截只是个不让你进入美丽花园的巨人,童话故事就是这么说的。这是修改后的拦截代码
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
boolean result = helper.shouldInterceptTouchEvent(ev);
float curX = ev.getX();
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = curX;
break;
case MotionEvent.ACTION_MOVE:
if (Math.abs(curX - startX) > helper.getTouchSlop()){
result = true;
}
break;
} return result;
}
第一行代码可以保证你把系统默认的拦截都走一遍,后面的就是判断用户滑动的距离超过了系统认定的最小滑动距离,我们就拦截下来。就这么简单的处理,你在向右滑,就还是被swipeLayout拦截,子view的点击事件就不会生效,你单纯去点击,当然也不会进入我们的判断,swipeLayout就正常的分发。至此,点击事件的坑就踩到这里了。看到这里,你会发现,废话那么多,才加了10行左右的代码,看别人的博客的话,别人直接告诉你,重写某某回调,点击事件就有了,那当然很省事,但这个探索的过程,我认为是很值得的,因为我经常闲的蛋疼。
ViewDragHelper的点击事件处理的更多相关文章
- UITableViewCell上的按钮点击事件处理
转自: http://www.aichengxu.com/view/42871 UITableViewCell上的按钮点击事件处理,有需要的朋友可以参考下. 今天突然做项目的时候,又遇到处理自定义的 ...
- Android零基础入门第66节:RecyclerView点击事件处理
前面两期学习了RecyclerView的简单使用,并为其item添加了分割线.在实际运用中,无论是List还是Grid效果,基本都会伴随着一些点击操作,那么本期就来一起学习RecyclerView的点 ...
- 在多行列表中id同名的<a>标签点击事件处理方法
Struts2标签 问题描述:最近项目中在使用struts迭代标签动态生成列表的过程中,由于每一行li元素中包含<a>超链接,如下图 一开始超链接是这样的<a href=“#” id ...
- Android学习笔记(1):常用按钮点击事件处理方式
1.从布局文件获取对应的控件然后对其添加点击监听器. Button loginBtn; @Override protected void onCreate(Bundle savedInstanceSt ...
- iOS中按钮点击事件处理方式
写在前面 在iOS开发中,时常会用到按钮,通过按钮的点击来完成界面的跳转等功能.按钮事件的实现方式有多种,其中 较为常用的是目标-动作对模式.但这种方式使得view与controller之间的耦合程度 ...
- 点击事件处理, 以及hitTest:withEvent:实现
发送触摸事件后, 系统会将事件添加到系统UIApplication的事件管理队列中 UIApplication会在事件队列的最前端取出事件,然后分发下去,以便处理, 通常会把事件首先分发给KeyWin ...
- jquery TypeError: $(...).live is not a functio,动态添加class的点击事件处理
jq版本更新后无live函数的处理.TypeError: $(...).live is not a function jquery live函数语法 jquery版本更新, 发现一个问题: jq自带的 ...
- iOS 子视图超出父视图范围点击事件处理!
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{ UIView *view = [super hitTest:point ...
- iOS UITextView点击事件处理
自定义一个UITextView UITextView 的selectedRange 影响 selectedTextRange 改变前者可影响后者 self.selectedRange -->se ...
随机推荐
- 粒子群优化算法(PSO)之基于离散化的特征选择(FS)(二)
欢迎大家关注我们的网站和系列教程:http://www.tensorflownews.com/,学习更多的机器学习.深度学习的知识! 作者:Geppetto 前面我们介绍了特征选择(Feature S ...
- 使用FME将CAD中块参照数据转换为shp数据
暴露出需要导出的字段值,首先在数据查看器中看看CAD中各个图层分别有哪些隐含的字段. CAD快参照中含有多个部分,需要将点按照原始编码聚合成一个点. 属性字段创建,并按照属性字段一一对应CAD中的字段 ...
- Linux/CentOS7搭建Anaconda运行环境
1. 安装miniconda 下载并安装miniconda到$HOME/.miniconda/ #从官网下载 wget -c "https://repo.anaconda.com/minic ...
- 常见Web安全漏洞--------sql注入
SQL注入:利用现有应用程序,将(恶意)的SQL命令注入到后台数据库执行一些恶意的操作.在mybatis 中比较容易出现:${} 会发生sql 注入问题 #{}: 解析为一个 JDBC 预编译语句(p ...
- IOS 获取系统时间戳
IOS 获取系统时间戳常用方法 通用方法有如下三种: NSLog(); NSDate* dat = [NSDate dateWithTimeIntervalSinceNow:]; NSTimeInte ...
- 模块 configparser 配置文件生成修改
此模块用于生成和修改常见配置文档 1.来看一个好多软件的常见配置文件格式如下***.ini [DEFAULT] ServerAliveInterval = 45 Compression = yes C ...
- Synchronized锁机制和ReentrantLock
Synchronized Java中的每个对象都可以作为锁. 普通同步方法,锁是当前实例对象. 静态同步方法,锁是当前类的class对象. 同步代码块,锁是括号中的对象. 锁的内部机制 一般锁有4种状 ...
- CodeForces 687A NP-Hard Problem
Portal:http://codeforces.com/problemset/problem/687/A 二分图染色 好模板题 有SPJ 值得注意的是,因为C++的奇妙的运算机制 若在vector变 ...
- vulnhub~incllusiveness
这个机子相对简单一点,但是也是从中发现了自己不少问题 技能一: nmap 扫描发现了21,22 ,80三个端口,并且ftp服务允许匿名登录,在pub目录下面有writeable权限,这就好办了.我以 ...
- 浅谈Python导入外部文件
import 和 from ... import * 有什么区别? 例如我写了个模块hello.py def print_func(args): print("Hello " + ...