《View的事件体系》(三)弹性滑动

    xiaoxiao2021-03-25  76

               在《View的事件体系》(二)中,我们介绍了几种实现View滑动的方法,可以看出实现起来并不复杂,但是实现效果略显生硬,最理想的是渐进式的滑动,也就是弹性滑动。实现弹性滑动的方法很多,但都是一个思想:就是把一个大的滑动分成若干小的滑动并在一定的时间段内完成。下面介绍几种实现的方法:

     

    (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的computeScroll和Scroller配合才能完成弹性滑动,他不断地让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的工作原理系列博文,便能进行进行灵活的扩展了。

     

    转载请注明原文地址: https://ju.6miu.com/read-15840.html

    最新回复(0)