前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >onTouchEvent(二) 使用Scroller实现黏性滑动的ScrollView

onTouchEvent(二) 使用Scroller实现黏性滑动的ScrollView

作者头像
用户1907613
发布2018-07-20 15:34:16
1K0
发布2018-07-20 15:34:16
举报
文章被收录于专栏:Android群英传

前言

本篇文章是之前投稿的一位读者的第二篇文章,也是他的实践之路,自己去实现一些滑动的特效,是掌握Android触控知识的一个非常好的方法,希望大家能够从他的Demo中获得一些新的感悟。

另外,昨天我发了一篇一触即发——App启动优化最佳实践,但是由于时间比较紧,只能趁着中午午休的时候发,所以,很多人可能没有看见,这里再给大家推荐下,希望大家能够不断优化自己的App。

上一篇博文onTouchEvent(一) 你所必须知道的坐标详解介绍了onTouchEvent()手势控制相关的一些坐标概念,这篇文章结合上一篇内容加上Scroller实现一个简单的带黏性滑动的ScrollView。

思路

  1. 滑动的时候判断最终偏移量是不是超出了子view(ViewGroup内容)的范围,如果超出了就限制不让其超出,这样就可以做出一个滑动的ScrollView并且不会滑出界
  2. 当松手(action_up)的时候判断当前偏移量在该子view的什么位置,如果小于三分之一就滑动回该view的头部,如果超出三分之二就滑动到下个view

首先看看我们需要做些什么,自定义View要复写的方法有好几个,我们要复写的有: 1. onMeasure() 2. onLayout() 3. onTouchEvent() 4. computeScroll()

因为是ViewGroup需要计算、定位子View所以需要复写1和2两个函数。 3不用说了,要实现滑动功能必须要实现的函数。 4这是配合Scroller使用的一个函数。

首先介绍下Scroller这个类,这个类是一个工具,并不是实际UI操作。这个工具提供的功能是提供差值计算,就像属性动画一样,要做一个平滑过渡的动画需要用到差值器来辅助提供偏移差值。

下面是一个不使用Scroller的Demo。

差别很明显。

onMeasure()没什么好说的,遍历子view,测量子view。

onLayout

要说明的都已经在注释上了。

onTouchEvent

首先提醒下getScrollY()、getScrollX()这两个方法获取的是当前的偏移量,初始状态都为0,左移累加正值,右移累加负值,上移累加正值,下移累加负值。如果看不懂其中坐标操作等请参考前一篇文章 onTouchEvent(一) 你所必须知道的坐标详解

该说明的都在注释里标明了,毕竟后面解释的话来回滚动很麻烦。

startScroll()还有一个重载。

public void startScroll(int startX, int startY, int dx, int dy, int duration)

自己设定操作的时间,上面那个重载是用得默认值250.

computeScroll()

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了…

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2016-11-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 群英传 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 思路
  • onLayout
  • onTouchEvent
  • computeScroll()
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档