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 ()这个方式,那么看看它什么情形下会阻挡事宜。

ViewDragHelper的点击事宜处置

 

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

ViewDragHelper的点击事宜处置  

——————————————————————————————————————————————————-

ViewDragHelper的点击事宜处置

——————————————————————————————————————————————————————

ViewDragHelper的点击事宜处置  

————————————————————————————————————————————————–

ViewDragHelper的点击事宜处置

EF多租户实例:演变为读写星散

从下往上看的话,你会发现在viewDragHelper的阻挡方式中,当你一步步走完tryCaptureViewForDrag时,mDragState会被赋值即是STATE_DRAGGING。凭据前面提过,子view是一定要消耗down的,接下来的move,从外往内通报,而且子view也没有设置不允许父view阻挡的标志,那么父view的阻挡方式就会一直挪用,也就是shouldInterceptTouchEvent会一直挪用。上面action =move是一直能进来的,那tryCaptureViewForDrag为啥不走呢,缘故原由很明了了:就是前面的pastSlop一直即是false嘛!从pastSlop 的赋值情形来看,它的效果跟checkTouchSlop有直接的关系:接着看图:

ViewDragHelper的点击事宜处置

  在上一篇博客中,我们重写了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到了干了什么好事:

ViewDragHelper的点击事宜处置

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

ViewDragHelper的点击事宜处置

圈内里提前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行左右的代码,看别人的博客的话,别人直接告诉你,重写某某回调,点击事宜就有了,那固然很省事,但这个探索的历程,我以为是很值得的,由于我经常闲的蛋疼。

原创文章,作者:2d28新闻网,如若转载,请注明出处:https://www.2d28.com/archives/6270.html