美文网首页
Android 属性动画(二)

Android 属性动画(二)

作者: yoosir | 来源:发表于2016-09-21 01:35 被阅读0次

    上一篇 Android 属性动画(一) 介绍了Property Animator 的基本用法。今天继续了解Property Animator 的Evaluator、Interpolator 和 xml 文件定义Animator 的相关知识和用法。

    Evaluator 求值器

    直接贴源码:

    public interface TypeEvaluator<T> {    
    /**     
        * This function returns the result of linearly interpolating the start and end values, with   
        * <code>fraction</code> representing the proportion between the start and end values. The     
        * calculation is a simple parametric calculation: <code>result = x0 + t * (x1 - x0)</code>,    
        * where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,     
        * and <code>t</code> is <code>fraction</code>.     
        * 
        * @param fraction   The fraction from the starting to the ending values     
        * @param startValue The start value.     
        * @param endValue   The end value.     
        * @return A linear interpolation between the start and end values, given the     
        *         <code>fraction</code> parameter.     
        */    
    public T evaluate(float fraction, T startValue, T endValue);
    }
    

    源码很简短,就一个方法,默认实现就是 根据fraction 通过 result = x0 + t * (x1 - x0) 公式计算返回一个中间值。
    那么 fraction 这个参数是多少呢?通过ValueAnimator 的setEvaluator() 方法找到源码:

    boolean animationFrame(long currentTime) {    
        boolean done = false;
        switch (mPlayingState) {
        case RUNNING:
        case SEEKED:
            float fraction = mDuration > 0 ? (float)(currentTime - mStartTime) / mDuration : 1f;
            if (mDuration == 0 && mRepeatCount != INFINITE) {
                // Skip to the end 
               mCurrentIteration = mRepeatCount;
                if (!mReversing) {
                    mPlayingBackwards = false;
                }
            }
            if (fraction >= 1f) {
                if (mCurrentIteration < mRepeatCount || mRepeatCount == INFINITE)
                {                
                    // Time to repeat
                    if (mListeners != null) {
                        int numListeners = mListeners.size();
                        for (int i = 0; i < numListeners; ++i) {
                            mListeners.get(i).onAnimationRepeat(this);
                        }
                    }
                    if (mRepeatMode == REVERSE) {
                        mPlayingBackwards = !mPlayingBackwards;
                    }
                    mCurrentIteration += (int) fraction;
                    fraction = fraction % 1f;
                    mStartTime += mDuration;
                    // Note: We do not need to update the value of mStartTimeCommitted here
                    // since we just added a duration offset.
                } else {
                    done = true;
                    fraction = Math.min(fraction, 1.0f);
                }
            }
            if (mPlayingBackwards) {
                fraction = 1f - fraction;
            }
            animateValue(fraction);
            break;
        }
        return done;
    }
    
    void animateValue(float fraction) {
        fraction = mInterpolator.getInterpolation(fraction);
        mCurrentFraction = fraction;
        int numValues = mValues.length;
        for (int i = 0; i < numValues; ++i) {
            mValues[i].calculateValue(fraction);
        }
        if (mUpdateListeners != null) {
            int numListeners = mUpdateListeners.size();
            for (int i = 0; i < numListeners; ++i) {
                mUpdateListeners.get(i).onAnimationUpdate(this);
            }
        }
    }
    

    在 ValueAnimator 类中有两个方法,可以看到在 animationFrame 方法就是 得到一个已完成时间在总时长的比例值(0~1)并赋值给 fraction,在 animateValue 方法中 调用了 mInterpolator.getInterpolation() (就是 插值器,后面会介绍) 目的就是修正 fraction 。所以我们知道 fraction 是一个0~1 的值。现在看下自定义Evaluator 的代码:

    //定义了一个 PointF 类型的 Evaluator ,实现 view 的抛物线变化
    //默认 TypeEvaluator View 在X,Y方向都是匀速的。
    //自定义后,View的Y方向是变速的。
    
    ValueAnimator valueAnimator = ValueAnimator.ofObject(new TypeEvaluator<PointF>(){
        @Override    public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
            // y 方向是一个变速        PointF point = new PointF();
            point.x = startValue.x + fraction * (endValue.x - startValue.x) ;
            point.y = (float) (startValue.y + Math.pow(fraction , 2) * (endValue.y - startValue.y));
            return point;
        }},
    new PointF(0,0),new PointF(400,1000));
    valueAnimator.setDuration(3000);
    valueAnimator.setInterpolator(new LinearInterpolator());
    valueAnimator.start();
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
             @Override    
            public void onAnimationUpdate(ValueAnimator animation)    {
            PointF point = (PointF) animation.getAnimatedValue();
            animView.setX(point.x);
            animView.setY(point.y);
        }});
    valueAnimator.start();
    

    Interpolator 插值器

    本来想写下Interpolayor的源码分析的,但看到一篇 Interpolayor的分析文章后,感觉自己也不会写的比这个好,所以还是不写了,借鉴和学习这篇文章 李海珍大神的 android动画(一)Interpolator。膜拜!!!
    一下是从 大神文章中摘抄的部分,图文并茂,讲解很详细,大家学习下!

    二:简单插值器分析
    ** 注意下面的图,对应你脑海中的插值的大小应该是斜率。**

    package android.view.animation;
    import android.content.Context;
    import android.content.res.TypedArray;
    import android.util.AttributeSet;
    /**
     *
     * 一个开始很慢然后不断加速的插值器。 
     * <hr/>
     * An interpolator where the rate of change starts out slowly and
     * and then accelerates.
     *
     */
    public class AccelerateInterpolator implements Interpolator {
         private final float mFactor; private final double mDoubleFactor;
         public AccelerateInterpolator() {
            mFactor = 1.0f;
            mDoubleFactor = 2.0;
         }
         /**     
           * Constructor
           *
           * @param factor
           * 动画的快慢度。将factor设置为1.0f会产生一条y=x^2的抛物线。增加factor到1.0f之后为加大这种渐入效果(也就是说它开头更加慢,结尾更加快)
           * <br/>Degree to which the animation should be eased. Seting
           * factor to 1.0f produces a y=x^2 parabola(抛物线). Increasing factor above
           * 1.0f exaggerates the ease-in effect (i.e., it starts even   * slower and ends evens faster)
          */
          public AccelerateInterpolator(float factor) {
            mFactor = factor;
            mDoubleFactor = 2 * mFactor;
          } 
          public AccelerateInterpolator(Context context, AttributeSet attrs) {
            TypedArray a =context.obtainStyledAttributes(attrs,com.android.internal.R.styleable.AccelerateInterpolator);
            mFactor = a.getFloat(com.android.internal.R.styleable.AccelerateInterpolator_factor, 1.0f);
            mDoubleFactor = 2 * mFactor;
            a.recycle();
          }
          @Override 
          public float getInterpolation(float input) {
             if (mFactor == 1.0f) {
                 return input * input;  
              } else {
                  return (float)Math.pow(input, mDoubleFactor);
              } 
          }
    }
    

    加速的快慢度由参数fractor决定。
    当fractor值为1.0f时,动画加速轨迹相当于一条y=x^2的抛物线。如下图:


    当fractor不为1时,轨迹曲线是y=x^(2*fractor)(0<x<=1)的曲线。
    示例:当fractor为4时,插值器的加速轨迹曲线如下图:

    如果你在使用AccelerateInterpolator时,想要那种一开始很慢,然后突然就很快的加速的动画效果的话。
    就将fractor设置大点。
    你可以到这里调试下你想要的抛物线效果:http://www.wolframalpha.com/input/?i=x%5E%282*3%29%280%3Cx%3C%3D1%29

    Android提供的一个不同factor的加速插值器:
    (1)accelerate_cubic, factor为1.5

    xml 文件定义Animator

    大家应该都在xml 文件定义过 帧动画 和 补间动画。今天,我们就在xml中定义属性动画,来看看有什么区别。
    先在 res 文件下创建 anmator 文件夹,在创建 res/animator/animator_set.xml 文件:

    <?xml version="1.0" encoding="utf-8"?>
    <set xmlns:android="http://schemas.android.com/apk/res/android"    
        android:ordering="together">
        <objectAnimator
            android:duration="1000"
            android:propertyName="scaleX"
            android:valueFrom="1"
            android:valueTo="0.5">
        </objectAnimator>
        <objectAnimator
            android:duration="1000"
            android:propertyName="scaleY"
            android:valueFrom="1"
            android:valueTo="0.5">
        </objectAnimator>
    </set>
    

    这个文件是实现 同时缩放XY轴的动画集合,我们可以看到 set 标签 动画集合有个
    android:ordering 属性,android:ordering 有两个值 :together(同时执行),sequentially (顺序执行)。接下来在代码中加载动画:

    // 加载动画
    Animator anim = AnimatorInflater.loadAnimator(this, R.animator.animator_set);
    //设置 缩放的中心点
    animView.setPivotX(0);
    animView.setPivotY(0);
    //显示的调用invalidate
    animView.invalidate();
    anim.setTarget(animView);
    anim.start();
    

    如上,将 animView 设为target 就可以了。 当然,缩放 和旋转都可以设置中心点的,我们将缩放的中心点设置在了 (0,0),默认都是在对象中心点。如果,只想实现单个动画,可以在xml 中去掉 set标签。

    下面是总结
    今天介绍了 Property Animator 的 Evaluator 、Interpolator 和 xml 定义,我们可以跟愉快的实现酷炫的动画啦。当然,在看了Interpolator 的文章后,还是佩服的五体投地的,我们要努力,像大神看齐!
    接下来,我会总结下 ** 布局动画(Layout Animations)** ,然后就是 属性动画实战啦,233333。fighting!!!

    源码,源码中还有我之前写的防直播打赏礼物动画效果。欢迎大家指教!

    相关文章

      网友评论

          本文标题:Android 属性动画(二)

          本文链接:https://www.haomeiwen.com/subject/juaoettx.html