滚来滚去,滚来滚去...Scroller完全解析
API:
1 mScroller.getCurrX() //获取mScroller当前水平滚动的位置
2 mScroller.getCurrY() //获取mScroller当前竖直滚动的位置
3 mScroller.getFinalX() //获取mScroller最终停止的水平位置
4 mScroller.getFinalY() //获取mScroller最终停止的竖直位置
5 mScroller.setFinalX(int newX) //设置mScroller最终停留的水平位置,没有动画效果,直接跳到目标位置
6 mScroller.setFinalY(int newY) //设置mScroller最终停留的竖直位置,没有动画效果,直接跳到目标位置
7
8 //滚动,startX, startY为开始滚动的位置,dx,dy为滚动的偏移量, duration为完成滚动的时间
9 mScroller.startScroll(int startX, int startY, int dx, int dy) //使用默认完成时间250ms
10 mScroller.startScroll(int startX, int startY, int dx, int dy, int duration)
11
12 mScroller.computeScrollOffset() //返回值为boolean,true说明滚动尚未完成,false说明滚动已经完成。这是一个很重要的方法,通常放在View.computeScroll()中,用来判断是否滚动是否结束。
Scroller和OverScroller这两个类是AndroidUI框架下实现滚动效果最关键的类,ScrollView内部的实现也是使用的OverScroller,所以熟练的使用这两个类的相关API,可以让我们满足大部分的开发需求。
在View类里面,有两个和滚动相关的方法,scrollTo()和scrollBy:这两个方法可以实现View内容的移动,注意,是内容,不是位置!是移动,不是滚动!什么叫做内容呢?比如说一个TextView,如果使用scrollTo(),那么移动的是里面的文字,而不是位置,scrollBy()也是一样的。那么为什么是移动,不是滚动呢?这是因为这两个方法完成的都是瞬间完成,即瞬移,而不是带有滚动过程的滚动,所以说,如果要实现效果比较好的滚动,光靠View自带的方法还是不行滴,还是要Scrollers出马~
但是Scrollers并不是控制View进行滚动,包括内容或者位置,Scrollers只是一个控件移动轨迹的辅助计算类,如果你想滚,他能帮你计算什么时间应该滚到什么位置,但是滚不滚,全靠你自觉~所以说,滚动位置由Scrollers计算出来了,我们在什么时候滚呢?滚多少呢?这时候,就要View的一个回调函数computeScroll()出马了。
Scroller这个类理解起来有一定的困难,刚开始接触Scroller类的程序员可能无法理解Scroller和View系统是怎么样联系起来的。我经过自己的学习和实践,对Scroller的用法和工作原理有了一定的理解,在这里和大家分享一下,希望大家多多指教。
首先从源码开始分析:
ViewGroup.java
- @Override
- protected void dispatchDraw(Canvas canvas) {
- .......
- .......
- .......
- .......
- for (int i = 0; i < count; i++) {
- final View child = children[i];
- if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null)
- {
- more |= drawChild(canvas, child, drawingTime);
- }
- .......
- .......
- .......
再看看drawChild函数:
- protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
- ................
- ................
- child.computeScroll();
- ................
- ................
- }
看到这里,我想大家应该就明白了,在父容器重画自己的孩子时,它会调用孩子的computScroll方法, 我们看看View里面的computeScroll()做了些什么
- /**
- * Called by a parent to request that a child update its values for mScrollX
- * and mScrollY if necessary. This will typically be done if the child is
- * animating a scroll using a {@link android.widget.Scroller Scroller}
- * object.
- */
- public void computeScroll() {
- }
duang!空的!不过没事,看看注释,就是说,如果我们用Scroller实现一个滚动动画的时候,这个方法就会被调用: 被谁调用呢?parent,谁改变呢?child。所以一般来说,这个方法可以用来更新mScrollX和mScrollY,但是其实不光可以改变这些,我们还能做其他事情。
如果我们调用Scroller.startScroll(int startX, int startY, int dx, int dy),那么我们就可以在computeScroll()里面执行实际的操作了,就像下面这样
- @Override
- public void computeScroll() {
- // 先判断mScroller滚动是否完成
- if (mScroller.computeScrollOffset()) {
- // 这里调用View的scrollTo()完成实际的滚动
- scrollTo( mScroller.getCurrX(), mScroller .getCurrY());
- // 必须调用该方法,否则不一定能看到滚动效果
- invalidate();
- }
- super.computeScroll();
- }
Scroller.computeScrollOffset方法是来判断滚动过程是否完成的,如果没有完成,就需要不停的scrollTo下去,所以在最后需要加一个invalidate(),这样可以再次触发computScroll,直到滚动已经结束。
其实说到这里,有的同学可能比较迷惑,OverScroller和Scroller有什么区别呢?
事实上,这两个类都属于Scrollers,Scroller出现的比较早,在API1就有了,OverScroller是在API9才添加上的,出现的比较晚,所以功能比较完善,Over的意思就是超出,即OverScroller提供了对超出滑动边界的情况的处理,这两个类80%的API是一致的,OverScroller比Scroller添加了一下几个方法
☞ isOverScrolled()
☞ springBack(int startX, int startY, int minX, int maxX, int minY, int maxY)
☞ fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY, int overX, int overY)
☞ notifyHorizontalEdgeReached(int startX, int finalX, int overX)
☞ notifyVerticalEdgeReached(int startY, int finalY, int overY)
从名字也能看出来,都是对Over功能的支持,其他的API都一样,所以介绍通用API的时候,并不区分OverScroller和Scroller。
下面简单介绍一下常用的API。
☞ computeScrollOffset() 这个就是来判断当前的滑动动作是否完成的,用法很单一,就是在computeScroll()里面来做判断滚动是否完成
☞ getCurrX(),getCurrY() 这个就是获取当前滑动的坐标值,因为Scrollers只是一个辅助计算类,所以如果我们想获取滑动时的时时坐标,就可以通过这个方法获得,然后在computeScroll()里面调用
☞ startScroll(int startX, int startY, int dx, int dy) 用来开始滚动,这个是很重要的一个触发computeScroll()的方法,调用这个方法之后,我们就可以在computeScroll里面获取滚动的信息,然后完成我们的需要。这个还有一个带有滚动持续时间的重载函数,可以根据需求自由使用。特别要注意这四个参数,startX和startY是开始的坐标位置,正数左上,负数右下,dx、dy同理,当在computeScroll()获取getCurrX()的时候,变化范围就与这里的设置有关。
☞ fling(int startX, int startY, int velocityX, int velocityY, int minX, int maxX, int minY, int maxY) 这个方法也很重要,如果你想实现滑动之后,布局能够根据移动速度,慢慢减速的话,就需要用这个来实现,这里需要加速度的参数,我们可以通过VelocityTracker这个类来获取,然后使用。
☞ getFinalX(),getFinalY() 这个是用来获取最终滑动停止时的坐标
☞ isFinished() 用来判断滚动是否结束
【参考资料】
滚来滚去,滚来滚去...Scroller相关类使用大揭秘!!! -- 赵凯强
Android Scroller完全解析,关于Scroller你所需知道的一切 -- 郭霖
Android 带你从源码的角度解析Scroller的滚动实现原理 -- 夏安明
滚来滚去,滚来滚去...Scroller完全解析的更多相关文章
- git 删除本地分支和远程分支、本地代码回滚和远程代码库回滚
[git 删除本地分支] git branch -D br [git 删除远程分支] git push origin :br (origin 后面有空格) git代码库回滚: 指的是将代码库某分支退 ...
- 【GIT】git 删除本地分支和远程分支、本地代码回滚和远程代码库回滚
[git 删除本地分支] git branch -D br [git 删除远程分支] git push origin :br (origin 后面有空格) git代码库回滚: 指的是将代码库某分支退 ...
- 回滚的意义---JDBC事务回滚探究
JDBC手动事务提交回滚的常见写法一直是rollback写在commit的catch之后: try{ conn.setAutoCommit(false); ps.executeUpdate(); ps ...
- NESTED内部事务异常会回滚 外部事务不会回滚 ;内部事务没有异常,外部事务有异常 则整体事务都回滚
NESTED内部事务异常会回滚 外部事务不会回滚 :内部事务没有异常,外部事务有异常 则整体事务都回滚
- 【转】git 删除本地分支和远程分支、本地代码回滚和远程代码库回滚
转载自:http://m.blog.csdn.net/blog/lihongli528628/45483463 [git 删除本地分支] git branch -D br [git 删除远程分支] g ...
- 去大公司还是去小公司工作——要进大公司的核心部门(提升视野,锻炼技能),远离没真本事的小公司,要自我驱动 good
去大公司还是小公司工作?这个问题问大多数 IT 人都会选择前者.如果换一个问法,去大公司还是去初创公司(Startup)工作?或许有极小一部分人能改变一下决定 对于 IT 人来说,选择到大公司工作的理 ...
- strip() 只去头尾的,不能去中间
# b = st.strip("|") # strip() 只去头尾的,不能去中间
- Bat 参数去引号(各种去引号的奇葩方式,三种变量互转),普通变量不能直接去掉外层引号
很多情况下,我们需要脱除一个字符串中可能会存在的引号,然后在加上自己的引 号使其中的特殊字符(命令连接符& .| .&&.||,命令行参数界定符Space .tab . ; . ...
- Python怎么去写单元测试用例去测试hello world呢
逛着博客园,看到乙醇大佬的一篇随笔 https://www.cnblogs.com/nbkhic/p/9370446.html,于是就在想怎么测试这句hello world print('hello ...
随机推荐
- jQuery版AJAX简易封装
开发过程中,AJAX的应用应该说非常频繁,当然,jQuery的AJAX函数已经非常好用,但是小编还是稍微整理下,方便不同需求下,可以简化输入参数,下面是实例代码: $(function(){ /** ...
- Linux(九)__网络测试
1.确认ip地址.子网掩码.网关是正确的. ifconfig 2.确认局域网是互通的,访问别人的电脑.网关 ping 发送数据包接收数据包,设备是否联通 /etc/sysconfig/network- ...
- LAMP布署笔记
源代码软件的优点: 获得最新版,能及时修复bug: 能自行修改和定制: 源代码打包形式: .tar.gz和.tar.bz2格式居多: 完整性校验: md5sum校验工具 ...
- iosselect:一个js picker项目,在H5中实现IOS的下拉效果
iosselect是在webapp下的一个picker组件,可以轻松实现各类选择器效果.比如地区选择 时间选择 日期选择等. 下面是一个地址选择器demo截图,可以访问:http://zhoushen ...
- 手机游戏渠道SDK接入工具项目分享(一)缘起
#剧情章节 # 上周刚结束一个外包的项目,开发手机游戏渠道SDK聚合接入工具的,现在有空回顾整理一下这个项目开发过程,因涉嫌商业秘密不会提供项目代码,只谈下开发思路和掉过的坑. 本人多年从事手机互联网 ...
- Linux系统安装MySql步骤及截屏
➠更多技术干货请戳:听云博客 如下是我工作中的记录,介绍的是linux系统下使用官方编译好的二进制文件进行安装MySql的安装过程和安装截屏,这种安装方式速度快,安装步骤简单! 需要的朋友可以按照如下 ...
- ListView之点击展开菜单
一.概述 ListView点击item显示菜单是要实现这样的效果: 需要实现的逻辑如下: 1)点击一个普通item,展开当前菜单,同时关闭其他菜单 2)点击一个已展开的菜单,隐藏当前菜单 3)将展开菜 ...
- ListView之性能优化
listview加载的核心是其adapter,本文通过减少adapter中创建.处理view的次数来提高listview加载的性能,总共分四个层次: 0.最原始的加载 1.利用convertView ...
- Android开发案例 - 图库
本文不涉及UI方面的内容, 如果您是希望了解UI方面的访客, 请跳过此文. 本文将要详细介绍如何实现流畅加载本地图库. 像平时用得比较多应用, 如微信(见下图), 微博等应用, 都实现了图库功能, 其 ...
- 使用ABP EntityFramework连接MySQL数据库
ASP.NET Boilerplate(简称ABP)是在.Net平台下一个很流行的DDD框架,该框架已经为我们提供了大量的函数,非常方便与搭建企业应用. 关于这个框架的介绍我就不多说,有兴趣的可以参见 ...