前言
本篇文章是之前投稿的一位读者的第二篇文章,也是他的实践之路,自己去实现一些滑动的特效,是掌握Android触控知识的一个非常好的方法,希望大家能够从他的Demo中获得一些新的感悟。
另外,昨天我发了一篇一触即发——App启动优化最佳实践,但是由于时间比较紧,只能趁着中午午休的时候发,所以,很多人可能没有看见,这里再给大家推荐下,希望大家能够不断优化自己的App。
上一篇博文onTouchEvent(一) 你所必须知道的坐标详解介绍了onTouchEvent()手势控制相关的一些坐标概念,这篇文章结合上一篇内容加上Scroller实现一个简单的带黏性滑动的ScrollView。
首先看看我们需要做些什么,自定义View要复写的方法有好几个,我们要复写的有: 1. onMeasure() 2. onLayout() 3. onTouchEvent() 4. computeScroll()
因为是ViewGroup需要计算、定位子View所以需要复写1和2两个函数。 3不用说了,要实现滑动功能必须要实现的函数。 4这是配合Scroller使用的一个函数。
首先介绍下Scroller这个类,这个类是一个工具,并不是实际UI操作。这个工具提供的功能是提供差值计算,就像属性动画一样,要做一个平滑过渡的动画需要用到差值器来辅助提供偏移差值。
下面是一个不使用Scroller的Demo。
差别很明显。
onMeasure()没什么好说的,遍历子view,测量子view。
要说明的都已经在注释上了。
首先提醒下getScrollY()、getScrollX()这两个方法获取的是当前的偏移量,初始状态都为0,左移累加正值,右移累加负值,上移累加正值,下移累加负值。如果看不懂其中坐标操作等请参考前一篇文章 onTouchEvent(一) 你所必须知道的坐标详解
该说明的都在注释里标明了,毕竟后面解释的话来回滚动很麻烦。
startScroll()还有一个重载。
public void startScroll(int startX, int startY, int dx, int dy, int duration)
自己设定操作的时间,上面那个重载是用得默认值250.
computeScroll()是一个空实现的函数,父控件调用用于更新子View,操作的是mScrollX和mScrollY,也就是移动偏移量。
该函数在draw中被调用,故可以用来控制scroll。但其实一个空实现的函数,那怎么做才能达到我们要的效果呢?layout()重新设置布局位置,不过这个太麻烦了用起来,上一篇介绍的scrollTo()、scrollBy()是正统滑动的代码。
直接上代码就很直观了,但为什么要调用invalidate()来不断调用呢?很多文章(网上随便查)都是这么写的。
PS:其实我开始是相信大神们的,后面写着写着有自己的理解,就开始质疑了…然后注释掉跑了下,滑动是有时会黏性滚动有时不会,我才又相信大神们了囧rz。 说说我得思路,如果不对希望有人能给我指出,谢谢。
首先onTouchEvent()中调用了Scroller.startScroll()方法,该方法不涉及UI操作所以在后面调用了一次invalidate()让View去重绘,根据上面的computeScroll()的调用得知draw的时候会调用该方法,即invalidate()之后会被调用。里面通过scrollTo()来进行移动的操作,scrollTo()该方法源码中有一个函数postInvalidateOnAnimation()
效果跟invalidate()差不多,也会重绘,但是前面有个判断。
awakenScrollBars(int startDelay, boolean invalidate)该方法里面也有可能会调用invalidate(),但也只是有可能,里面有其他判断可能会过滤掉,所以终其原因就是有不会调动invalidate()的可能行存在,所以手动调用了一次invalidate()。
既然手动调用invalidate()就会重绘,也就会调用到computeScroll(),里面再判断Scroller的差值计算是否完毕,未完毕则继续移动就这样循环直至偏移到最终坐标。
附上布局文件
结束语
呼,终于完成这一篇了,医生让我一周一更,还是有点累的,之前的我辣么懒,不过坚持下来我就是赚到了,下面就这个主题还准备写一两篇,又要挤时间敲敲demo了…