不积跬步无以至千里
一、简介
最近项目需求:
HorizonScrollView做一个滑动布局,如下图,其中最多显示5个图标,锁屏两边有个界线来限制显示区域,下边有个随着图标超过5个会出现小白点,然后11个会出现3个小白点这个规律下去,然后通过滑动布局的位置控制小白点选中的位置
二、问题
由上边所述,因为两边是有界线的,所以会出现半个图标卡到边界上显示,因此咱们这里要做一个如果卡在半截的状态,就要自动滑动到一定位置来完整的显示几个图标,这样用户的体验会更好一点,因此需要咱们自己做一个滑动操作。
因此通过上边的想法在这个自定义的HorizonScrollView中的OnTouchEvent中对Action_Up进行滑动操作,于是按照上边的想法写代码,在Action_Up中进行滑动操作。
发现慢速滑动的时候会在Action_Up后,响应滑动事件,完美;但是发现在快速滑动的时候,后边的滑动方法不起效果;
Why?
三、问题分析
慢速滑动可以,快速滑动不可以,肯定就是快速滑动导致的原因,分析一下,快速滑动会导致这个HorizonScrollView怎样?当把HorizonScrollView设置的整体的Width比较长时,会发现快速滑动会让整个布局有惯性的效果,会等一会才会停下来。
再看一下源码中的ScrollBy、ScrollTo、SmoothScrollTo等方法,其实最终调用的都是ScrollTo方法,因此查看代码
路径:/frameworks/base/core/java/android/view/View.java
scrollTo方法
由上代码,其中设置去进行动画的移动需要判断 awakenScrollBars()方法,查看此方法如下:
可以看上边的return返回,翻译为如果动画还在进行返回true,否则返回false。
因此,咱们前边观察上可以看出,由于快速滑动后,有惯性还会继续滑动,如果此时去做ScrollTo方法,肯定上边有动画就是滑动,因此会返回true,因此方法是走不通的。
四、解决办法
上边的原因是因为快速滑动导致惯性直接去调用自己的滑动方法是不行的,需要等快速滑动的停止下来才可以,因此如何监听到HorizonScrollView的滑动停止,停止后再去做自己的ScrollTo方法即可。
于是寻找这个HorizonScrollView是否有滑动停止状态的返回,但是经过翻看并没有,其实HorizonScrollView嵌套的就是OverScroller,其实OverScroller有一个isFinished()方法能判断其中的滑动是否停止,但是这个方法不是公共方法,不能使用,而且这个方法赋值的变量来对滑动状态的变量也是私有变量,我们无法使用。
方案:
内部不提供方法,咱们只能自己判断了,这里有个getScrollX()方法,因此当判断上一次的getScrollX()与当前的值是一样的就可以判断滑动已停止。
代码如下:
private int oldScroolX = -1;
//滑动是否结束方法
private boolean getScrollViewScrollFlag() {
int scrollX = getScrollX();
if (oldScroolX != -1 && scrollX == oldScroolX) {
return false;
}
oldScroolX = scrollX;
return true;
}
//OnTouchEvent中的Action_Up中的滑动方法
private void autoScrollLayout() {
// Do not auto scroll the layout during scroll.
int time = 100;
int mFinalLayoutScrollLocation = getScrollX();
if (getScrollViewScrollFlag()) {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
autoScrollLayout();
}
}, time);
return;
}
//设置滑动方法
smoothScrollBy(mMoveScrollSize, 0);
}
问题就解决了。
话外篇:
其实其中开发过程中在Action_Move中smoothScrollBy方法无滑动效果,我怀疑也是因为滑动过程不让去做粗糙滑动导致。