Android 动画原理


       Android 要做出炫的显示效果来就离不开动画。何为动画?当一个View 随时间变化而移动、放大、透明度变化等都能产生动画,同样连续的帧变化也能形成动画。

       本文结合一动画实例来详细介绍Android的动画机制及Scroller类。如图1所示,在T1时刻,View的中心位置为X1,T2时刻中心位置为X2,从T1到T2的 delta =T2-T1的时间段中View 从X1位置移动到X2位置,同时逐步放大到原来大小的1.5倍,中间的虚线框表示某一时刻时View的位置和大小。很显然这是一个动画过程,在一定时间内实现了View 的移动和放大,当然也可以去逐步修改View的透明度。
      
                                图1, 动画移动实例
         图1 过程的位置移动可以通过Android Scroller 来实现,在Android 控件中,Gallery、ViewPager都使用了Scroller来实现滚动动画,理解Scroller对实现好的动画效果十分有用。下面介绍一下Scroller 类,Scroller 支持滚动模式(SCROLL_MODE)和Fling 模式(FLING_MODE),这里重点介绍SCROLL_MODE,fling模式也是类似的,无非是插值函数的差异,后面也有介绍。

      一: Scroller  关键API 分析
     
  1.  public void startScroll(int startX, int startY, int dx, int dy, int duration){
             mMode = SCROLL_MODE;
             mFinished = false;
             mDuration = duration;     // 滚动时长
             mStartTime = AnimationUtils.currentAnimationTimeMillis(); //当前滚动时间
             mStartX = startX;      // 滚动起始位置
             mStartY = startY;
             mFinalX = startX + dx;     // 滚动结束位置
             mFinalY = startY + dy;
             mDeltaX = dx;                  // 滚动距离
             mDeltaY = dy;
             mDurationReciprocal = 1.0f / (float) mDuration;     //滚动时长的倒数
          }
       Scroller 并不是真正实现View 的滚动,它只是用来记录及记录View 滚动位置的工具,如图1中的示例中,移动的duration 是T2-T1,X方向移动的dx 是X2-X1,Y方向无移动。因此在控制View 绘制的线程创建一个Scroller实例mScroller,通过mScroller.startScroll(0,0,X2-X1,0,T2-T1) 便实现了滚动的初始化。
 
 2.  
         public boolean computeScrollOffset() {
        if (mFinished) {
            return false;
        }
        // 计算已经消耗掉的时间
        int timePassed = (int)(AnimationUtils.currentAnimationTimeMillis() - mStartTime);
        
        if (timePassed < mDuration) {
           // 消耗的时间未达到动画时长
            switch (mMode) {
            case SCROLL_MODE:
               // 计算消耗掉的时间占动画总时间的比例
                float x = timePassed * mDurationReciprocal;
                
               // 根据插值函数,计算出当前时刻,View 需要滚动到的位置,插值函数在后面介绍
                if (mInterpolator == null)
                    x = viscousFluid(x);
                else
                    x = mInterpolator.getInterpolation(x);
   
                mCurrX = mStartX + Math.round(x * mDeltaX);
                mCurrY = mStartY + Math.round(x * mDeltaY);
                break;
            case FLING_MODE:
               ... ... 
                break;
            }
        }
        else {
             // 如果消耗的时间已经达到动画时长了,那么直接移动到终点位置
            mCurrX = mFinalX;
            mCurrY = mFinalY;
            mFinished = true;
        }
        return true;
    }

    3.  
       public final int getCurrX() {
           return mCurrX;
    // 获取当前滚动位置
         }
        从Scroller中的上述两个方法可以看出,实现View的移动只需要通过一个线程不停的调用computeScrollOffset来判断是否移动完成,并获取到当前移动的位置,将View移动到对应位置即可。
       图1的动画,代码段示例如下:
  private AnimationRunnable  mAnimationRunnable = new FlingRunnable();
   mAnimationRunnable.mScroller.startScroll(0,0,X2-X1,0,T2-T1);

   private class AnimationRunnable implements Runnable{

        public AnimationRunnable () {
            mScroller = new Scroller(getContext());
        }
        
        @Override
        public void run() {

            
            final Scroller scroller = mScroller;
            boolean more = scroller.computeScrollOffset();
            final int x = scroller.getCurrX();
            int delta = mLastScrollX - x;

            if (delta > 0) {
              mView.offsetLeftAndRight(delta);    //移动view
              mView.setScaleX();   // 这里设置放大比例,其他放大比例可以根据实际情况计算,此处略去放大参数。  
              mView.setScaleY();
              invalidate();
            if (more) {
      // 继续滚动
                mLastScrollX = x;
                post(this);
 
            } else {
              mScroller.forceFinished(true);    //滚动结束
            }
        }
}
假如系统性能高,每次绘图的时间短,那么根据上面的分析可知从X1位置移动到X2位置绘制的帧数会越多,动画效果会越平滑,反之动画将没有那么流程。 

二:插值函数Interpolator
       画面移动过程要呈现不同的效果,可以通过不同的插值函数来实现。在构造Scroller时可以设置不同的插值函数来达到不同的动画效果,如我们经常看到的滑屏fling效果是移动速度逐渐变小最后停止下来,
       图2和图3分别是Scroller中FLING_MODE下速度与时间、位移与时间的关系图。
      
                             图2 fling 模式下速度与时间的关系曲线  

                      图3:fling模式下位移与时间的关系曲线
       Interpolator用于动画中的时间插值,不同的插值曲线能做出不同的动画效果,如匀速移动,加速移动,先加速后减速等等,这里不一一举例。只要理解了Android动画的原理,可以根据自己的需求来设计插值函数来实现更好的动画效果。






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值