Android开发——弹性滑动的两种实现方式

0. 前言  

欢迎转载,转载请注明出处:http://blog.csdn.net/seu_calvin/article/details/52538723

我们在Android开发——View滑动的三种实现方式中学习了如何进行View滑动,在第一种方法,利用ScrollByScrollTo进行滑动时,滑动效果是瞬间完成的,为了更好的用户体验,有时我们需要滑动有一个渐变的过程。这就是所谓的弹性滑动。

 

1.   延时策略

我们解决弹性滑动的第一反应可能就是采用延时策略,通过Handler发送并接收延时消息每次接收到消息便完成一次ScrollTo操作,从而实现弹性滑动的效果。核心代码展示如下:

[java]  view plain  copy
  1. public void handleMessage(Message msg) {   
  2.   switch(mag.what){  
  3. case SCROLL_FRACTION:{  
  4.     //if判断滑动还没有结束,结束则不再滑动和发送消息  
  5.     if(){  
  6. //通过滑动完成比例计算该次滑动片段的位置点scrollX,scrollY  
  7. View.scrollTo(scrollX,scrollY);  
  8. mHandler.sendEmptyMessageDelayed(SCROLL_FRACTION, 20);  
  9. }  
  10. break;  
  11. }  
  12. default:  
  13. break;  
  14. }  
  15. }  

上述这种利用Handler发送延时消息的方式比较简单,但是需要注意的是,由于系统的消息调度需要时间,完成这次弹性滑动的时间总是大于if条件判断为true的次数乘以20ms(延迟消息的发送时间间隔)

因此对弹性滑动完成总时间有精确要求的使用场景下,使用延时策略是一个不太合适的选择。


2.  Scroller的使用

2.1  系统提供的Scroller

利用系统提供给我们的Scroller类,我们可以很方便的实现弹性滑动。代码比较简单,都是模版化的,如下所示:

[java]  view plain  copy
  1. Scroller scroller = new Scroller(mContext);  
  2. private void smoothScrollTo(int destX, int destY){  
  3. int distanceX = destX - getScrollX();  
  4. int distanceY = destY - getScrollY();  
  5. //设置500ms的弹性滑动总时长  
  6. mScroller.startScroll(getScrollX(),getScrollY(),distanceX, distanceY, 500);  
  7. //重绘  
  8. invalidate();  
  9. }  
[java]  view plain  copy
  1. //该方法为空实现,因此需要重写  
  2. //该方法会被invalidate()方法触发执行  
  3. @override  
  4. public void computeScroll(){  
  5.     //判断滑动还没有结束  
  6. if(mScroller.computeScrollOffset()){  
  7.     //通过Scroller类拿到下一步要滑动到的位置  
  8.     scrollTo(mScroller.getCurrX(), mScroller.getCurrY());  
  9.     postInvalidate();  
  10. }  
  11. }  

这里说一下invalidate()postInvalidate()的区别

为了UI安全,invalidate()可在主线程直接调用刷新界面,而postInvalidate()会用Handler通知UI线程重绘屏幕,因此后者适用于子线程

 

2.2  自定义Scroller

上面介绍了调用系统提供的Scroller的使用方法,但是Scroller类的getCurrX()computeScrollOffset()等方法都是写死的。实现的弹性滑动是先快后慢的效果。

下面我们自行实现一个MyScroller类来完成匀速滑动的效果,同时也有助于理解系统Scroller类的实现原理。

[java]  view plain  copy
  1. /* 
  2.  * Created by SEU_Calvin on 2016/09/12 
  3.  * 计算位移距离的自定义Scroller 
  4. */  
  5. public class MyScroll{  
  6.     private int startX;  
  7.     private int startY;  
  8.     private int distanceX;  
  9.     private int distanceY;  
  10.     private int duration;  
  11.     //开始执行动画的时间  
  12.     private long startTime;  
  13.     //判断是否动画结束  
  14.     private boolean isFinish;  
  15.     //计算当前距离  
  16.     private long currentX;  
  17.     private long currentY;  
  18.     public MyScroll(Context context) {  
  19.     }  
  20.   
  21.     public long getCurrX() {  
  22.         return  currentX;  
  23.     }  
  24.     public long getCurrY() {  
  25.         return  currentY;  
  26.     }  
  27.   
  28.     public void startScroll(int startX, int startY, int distanceX, int distanceY, int duration) {  
  29.         this.startX = startX;  
  30.         this.startY = startY;  
  31.         this.distanceX = distanceX;  
  32.         this.distanceY = distanceY;  
  33.         this.duration = duration;  
  34.         this.startTime = SystemClock.uptimeMillis();  
  35.         this.isFinish = false;  
  36.     }  
  37.     /* 
  38.      * Created by SEU_Calvin on 2016/09/12 
  39.      * 判断是否滑动结束并改变将要被使用的currentX/Y 
  40.     */  
  41.     public boolean computeScrollOffset() {  
  42.         if(isFinish){  
  43.             return false;  
  44.         }  
  45.         //获得startTime到调用由于重绘导致computeScrollOffset()调用之间的passtime  
  46.         long passtime = SystemClock.uptimeMillis()-startTime;  
  47.         //计算currentX的值,指导下一步ScrollTo的位置  
  48.         //startX/Y <currentX/Y<= startX/Y + distanceX/Y  
  49.         if(passtime<duration){  
  50.             currentX = startX + distanceX*passtime/duration;  
  51.             currentY = startY + distanceY*passtime/duration;  
  52.         }else{  
  53.             //运行结束  
  54.             currentX = startX + distanceX;  
  55.             currentY = startY + distanceY;  
  56.             isFinish = true;  
  57.         }  
  58.         return  true;  
  59.     }  
  60. }  

我们只要在调用时改变调用的MyScroll类即可。其他代码不做修改。

具体滑动效果,如匀速,匀加速,先慢后快等效果完全可以由MyScroll中自己的算法来决定

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值