实现弹性滑动的方法很多,但都是一个思想:就是把一个大的滑动分成若干小的滑动并在一定的时间段内完成。下面介绍几种实现的方法:

 

(1)使用Scroller

     这种方法在《View的事件体系》(一)中已经贴出了源码,这里再分析一下:

Scroller scroller =new Scroller(context);
private void smoothScrollTo(int x,int y){
   int scrollX = getScrollX();
   int delta = x – scrollX;
   //1000秒内滑向x,慢慢移动
  scroller.startScroll(scrollX,0,delate,0,1000);
   invalidate();
}
@Override
public void computeScroll(){
  if(scroller.computeScrollOffset()){
     scrollTo(scroller.getCurrX(),scroller.getCurrY());
      postInvalidate();
}
}

Scroller和View是两个不同的个体,代码的思路就是让Scroller先移动,然后让View跟着Scroller的脚步进行移动。代码中我们构造先一个Scroller并在smoothScrollTo中调用他的startScroll方法,startScroll方法的作用就是保存这几个参数,从左到右分别是滑动的起始X,Y坐标,终点X,Y坐标和整个滑动过程所需要的时间。真正完成滑动的是invalidate(),invalidate会让View重新绘制,在View的draw方法中又会去调用computeScroll方法,在View中computeScroll方法是一个空实现,在上面的代码中已经给出了实现。在computeScroll中,我们看到mScroller.computeScrollOffset(),他的作用不仅是判断滚动是否结束,而且根据时间的流逝的百分比计算出scrollX和scrollY改变的百分比,还在里面对Scroller.mCurrX和Scroller.mCurrY进行了赋值,也就是在滚动的过程中,实时的更新CurrX、CurrY的坐标。scrollTo(scroller.getCurrX(),scroller.getCurrY())就是让View跟着scroller改变位置。postInvalidate方法会进行第二次重绘,过程和第一次一样,如此反复,直到滑动结束。

他不断地让View重绘,每一次重绘距滑动起始时间都会有一个时间间隔,通过这个时间间隔,Scroller得到View下次滑动到的位置,继而View通过scrollTo完成滑动。这种设计简直绝妙!

 

(2)使用动画

final int startX = 0;
    final int deltaX = 100;
    ValueAnimator  animator=ValueAnimator.ofInt(0,1).setDuration(1000);
     animator.addUpdateListener(newAnimatorUpdateListener(){
public void onAnimationUpdate(ValueAnimator animator){
    float fraction =animator.getAnimatedFraction();//fraction,分数
 button.scrollTo(stratX+(int)(deltaX*fraction),0);
}
}) ;
animator.start;

       在上面的代码中只是在1000ms内完成了整个动画过程。利用这个特性,我们就可以在动画的每一帧到来的时候获取动画完成的比例,进而根据这个比例计算出当前View所要滑动的距离。我们完全可以在onAnimationUpdate中加入其它想要的操作。

 

(3)延时策略

可以使用Handler或者View的postDelayed方法,也可以使用线程的sleep方法。对于前者我们利用postDelayed发送延时消息,在消息中让View滑动,接连不断的发送这种消息就可以实现弹性滑动的效果。对于后者来说通过在while循环中不断滑动View和sleep,就可以实现。下面以Handler为例:

private intmCount = 0;
intMESSAGE_SCROLL_TO = 0;
int FRAME_COUNT= 30;
int DELAYED_TIME= 33;
private Handlerhandler = new Handler(){
    public void handleMessage(Message msg){
       switch(msg.what){
          case MESSAGE_SCROLL_TO:{
             mCount++;
             if(mCount<= FRAME_COUNT){
                     float fraction = mCount/(float)FRAME_COUNT
                     int scrollX = (int)(fraction*100);
                    button.scrollTo(scrollX,0);
                     handler.sendEmptyMessageDelayed(MESSAGE_SCROLL_TO,DELAYED_TIME);
                     
}break;
}
default:
     break;
}
};
};

       介绍这几种方法时更侧重思想,但结合前几篇讲解MotionEvent等关键概念,以及View的工作原理系列博文,便能进行进行灵活的扩展了。