在上一篇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的点击事件处理的更多相关文章

  1. UITableViewCell上的按钮点击事件处理

    转自:  http://www.aichengxu.com/view/42871 UITableViewCell上的按钮点击事件处理,有需要的朋友可以参考下. 今天突然做项目的时候,又遇到处理自定义的 ...

  2. Android零基础入门第66节:RecyclerView点击事件处理

    前面两期学习了RecyclerView的简单使用,并为其item添加了分割线.在实际运用中,无论是List还是Grid效果,基本都会伴随着一些点击操作,那么本期就来一起学习RecyclerView的点 ...

  3. 在多行列表中id同名的<a>标签点击事件处理方法

    Struts2标签 问题描述:最近项目中在使用struts迭代标签动态生成列表的过程中,由于每一行li元素中包含<a>超链接,如下图 一开始超链接是这样的<a href=“#” id ...

  4. Android学习笔记(1):常用按钮点击事件处理方式

    1.从布局文件获取对应的控件然后对其添加点击监听器. Button loginBtn; @Override protected void onCreate(Bundle savedInstanceSt ...

  5. iOS中按钮点击事件处理方式

    写在前面 在iOS开发中,时常会用到按钮,通过按钮的点击来完成界面的跳转等功能.按钮事件的实现方式有多种,其中 较为常用的是目标-动作对模式.但这种方式使得view与controller之间的耦合程度 ...

  6. 点击事件处理, 以及hitTest:withEvent:实现

    发送触摸事件后, 系统会将事件添加到系统UIApplication的事件管理队列中 UIApplication会在事件队列的最前端取出事件,然后分发下去,以便处理, 通常会把事件首先分发给KeyWin ...

  7. jquery TypeError: $(...).live is not a functio,动态添加class的点击事件处理

    jq版本更新后无live函数的处理.TypeError: $(...).live is not a function jquery live函数语法 jquery版本更新, 发现一个问题: jq自带的 ...

  8. iOS 子视图超出父视图范围点击事件处理!

    - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{   UIView *view = [super hitTest:point ...

  9. iOS UITextView点击事件处理

    自定义一个UITextView UITextView 的selectedRange 影响 selectedTextRange 改变前者可影响后者 self.selectedRange -->se ...

随机推荐

  1. TensorFlow 基本变量定义,基本操作,矩阵基本操作

    使用 TensorFlow 进行基本操作的实例,这个实例主要是使用 TensorFlow 进行了加法运算. 包括使用 constant 常量进行加法运算和使用 placeholder 进行变量加法运算 ...

  2. OpenCV-Python 读取显示图像 | 五

    目标 在这里,你将学习如何读取图像,如何显示图像以及如何将其保存回去 你将学习以下功能:cv.imread(),cv.imshow(),cv.imwrite() (可选)你将学习如何使用Matplot ...

  3. POJ 3680 Intervals 最小费用最大流(MCMF算法)

    题意:给出 n ,k 表示接下来给你 n 段开区间,每段区间都有它的权值,问选出一些区间,使它的权值最大,并且在实轴上的每个点,不得超过 k次被覆盖. 思路:首先要理解建图思路,首先有一个基图,相邻点 ...

  4. 不可思议的hexo,五分钟教你免费搭一个高逼格技术博客

    引言 作为程序员拥有一个属于自己的个人技术博客,绝对是百利无一害的事,不仅方便出门装b,面试时亮出博客地址也会让面试官对你的好感度倍增.经常能在很多大佬的技术文章的文末,看到这样一句话: " ...

  5. coding++:解决Not allowed to load local resource错误-SpringBoot配置虚拟路径

    1.在SpringBoot里上传图片后返回了绝对路径,发现本地读取的环节上面出现了错误(Not allowed to load local resource),一开始用的是直接本地路径. 但是在页面上 ...

  6. Tainted canvases may not be exported的问题解决

    项目里使用到用canvas生成海报,在toDataURL报了这个错误Tainted canvases may not be exported. 原因就在于使用了跨域的图片,所以说是被污染的画布.解决方 ...

  7. Vertica的这些事(二)——SQL-Server、Oracle、MySQL和Vertica数据库常用函数对比

    SQL Server.Oracle.MySQL和Vertica数据库常用函数对比 Vertica数据库是HP公司新收购的用于BI方面的数据库. 绝对值 S:select abs(-1) value O ...

  8. Oracle ROWNUM用法

    很多朋友应该跟我一样有个疑问,为什么rownum > 5 的时候会查不到一条数据,用rownum < 5就可以查到数据,明明查询所有的时候rownum有很多啊,小朋友,你是不是有很多问号? ...

  9. 力软敏捷框架 jfGrid 使用例子之一

    百度了下关于力软敏捷框架 jfGrid的教程,基本没有,出来的全是jqGrid.好吧看来只能自己上手了 今天来讲讲列设置属性里数据格式化事件(formatter)的使用 常规的使用方式如上图所示. 先 ...

  10. Xshell连接Centos7

    13:53:10 2019-08-05 一个月暑假开始 学习搭建一个自己的博客 我是用阿里云的服务器搭建自己的博客 先利用XShell连接我的服务器 XShell下载地址:https://www.ne ...