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

前言

本篇文章是之前投稿的一位读者的第二篇文章,也是他的实践之路,自己去实现一些滑动的特效,是掌握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了…

原文发布于微信公众号 - Android群英传(android_heroes)

原文发表时间:2016-11-08

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏用户2442861的专栏

Markdown,你只需要掌握这几个

http://www.cnblogs.com/crazyant007/p/4220066.html

1311
来自专栏iKcamp

追溯 React Hot Loader 的实现

文:萝卜(沪江金融前端开发工程师) 本文原创,转载请注明作者及出处 如果你使用 React ,你可以在各个工程里面看到 Dan Abramov 的身影。他于...

47414
来自专栏hightopo

原 基于 HTML5 WebGL 的 3D

2916
来自专栏学海无涯

Python爬虫之BeautifulSoup

上一篇博文中提到用正则表达式来匹配数据项,但是写起来容易出错,如果有过DOM开发经验或者使用过jQuery的朋友看到BeautifulSoup就像是见到了老朋友...

41410
来自专栏CRPER折腾记

Vue 折腾记 - (7) 写一个挺不靠谱的Vue-Echarts组件

上基友社区看了下,发现对echarts的封装都是打包进去的...想想就还是算了.. 图表这货.说实在的,若不是整个系统大量用到,打包进去没必要...

872
来自专栏数据小魔方

rept——一个可以一键成图的神奇函数!

今天想跟大家分享一个特别有趣的函数——rept函数。 ▼ 这个函数,就如同它的名字一样,具有重复显示字符的功能。 如图所示,在A57单元格中有一个数字1,如果我...

3715
来自专栏QQ音乐前端团队专栏

前端水印生成方案

安全问题不能大意,对于一些比较敏感的内容,我们可以通过组合使用上述的水印方案,这样才能最大程度给浏览者警示的作用,减少泄密的情况,即使泄密了,也有可能追踪到泄密...

1.4K3
来自专栏更流畅、简洁的软件开发方式

【自然框架】n级下拉列表框的原理

  其实原理也很简单,分成两个部分,一个是服务器端,一个是客户端。   首先要设置记录集,这里用DataSet来装载,二级联动,里面就要有两个DataTable...

2647
来自专栏前端知识分享

Web前端面试宝典(最新)

html语义化让页面的内容结构化,结构更清晰,便于对浏览器、搜索引擎解析;即使在没有样式CSS情况下也以一种文档格式显示,并且是容易阅读的;

3443
来自专栏程序员的诗和远方

在React Native中优雅的使用iconfont

React Native大火大热,其中为了解决图标,易于修改,换颜色,高清等需求,iconfont的应用更是必不可少。 React Native中的ic...

5744

扫码关注云+社区

领取腾讯云代金券