天天看點

Android中的屬性動畫了解

Android中有補件動畫,幀動畫和屬性動畫這幾種常見動畫。屬性動畫是3.0系統後推出的比較強大的動畫。可以實作生活中大多數常見的動畫功能。最近學習,用到了屬性動畫,結合源碼和一些參考做一個記錄。

1.基本使用

屬性動畫中常用到類ValueAnimator,ObjectAnimator,屬性動畫就是通過改變對象的屬性實作動畫,這兩個類完成了對象的屬性從初始值到結束的值的變化。

常用的方法:ofFloat(),ofInt(),ofObject();等。這些方法都有很多不同的重載方法,提供不同的參數實作差異的功能。

其中有一個:ValueAnimator bizerAnimator = ObjectAnimator.ofObject(typeEvalautor, param, param,param);這個需要傳入一個估值器對象(TypeEvaluator)

其他方法:

bizerAnimator.setEvaluator();//設定一個估值器
  bizerAnimator.setRepeatCount();//設定重複執行次數
  bizerAnimator.setRepeatMode();//設定動畫重複的模式
  bizerAnimator.setTarget();//設定動畫添加一個對象
  bizerAnimator.setInterpolator();//設定一個插值器
           

這裡插值器和估值器是實作一些複雜效果的關鍵。

基本使用舉例:

ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f,1f);
        valueAnimator.setDuration(500);
        valueAnimator.start();
           

一個基本的用法就是三行代碼,實作500毫秒從0到1的變化;其實還可以傳入多個參數,這個ofFloat()方法參數是邊長參數。

ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f,0.6f,0.2f,1f);
        valueAnimator.setDuration(500);
        valueAnimator.start();
           

上面實作了從0到0.6到0.2再到1的變化。

ObjectAnimator類:

ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView,"translationX",0f,200f,0f);
                objectAnimator.setDuration(2000);
                objectAnimator.start();
           

對一個ImageView 實作從起始位置到200px在到原始位置的變化,對應的:

"translationX"
           

是ImageView 的一個屬性,這個屬性在ImageView 中有個對應的set方法:

imageView.setTranslationX(0);
           

這裡需要注意的一點就是: 在對一個對象進行操作的時候,第一個參數是對象示例,第二個參數一定是對應對象的一個屬性并且有一個set方法去設定這個屬性。動畫執行過程就是通過這個屬性設定值的。

2.組合使用

組合使用就是把不同的動畫效果放一起執行,可以是先後執行,也可以同時執行,這是實作一些複雜效果的關鍵。組合使用通過AnimatorSet 來組合。

比如對上的圖檔添加第一個移動,透明度變化和旋轉三種動畫,組合執行:

AnimatorSet animatorSet = new AnimatorSet();
                ObjectAnimator translation = ObjectAnimator.ofFloat(imageView,"translationX",0f,300f,0f);
                ObjectAnimator alpha = ObjectAnimator.ofFloat(imageView,"alpha",1f,0f,1f);
                ObjectAnimator rotationY = ObjectAnimator.ofFloat(imageView,"rotationY",0f,360f);
                //animatorSet.playSequentially(translation,alpha,rotationY);//按順序執行位置移動,透明度變化,和旋轉三個動畫效果。
                //animatorSet.play(translation).with(alpha).before(rotationY);//執行translation同時執行alpha 設定,在執行rotationY之前。
                animatorSet.playTogether(translation,alpha,rotationY);//三個同時執行
                animatorSet.setDuration(3000);
                animatorSet.start();
           

以上代碼建立了三個通話效果,通過不同的方法組合不同的執行效果。

知道了這些,我們還可以通過操作其他的對象屬性作出其他的效果來。

屬性動畫的基本使用就是這些,如果代碼操作不友善還可以寫xml,在項目中使用。直接在代碼中加載設定執行。

<set xmlns:android="http://schemas.android.com/apk/res/android">

    <objectAnimator
        android:duration="1000"
        android:propertyName="translationX"
        android:valueFrom="0dp"
        android:valueTo="100dp"
        android:valueType="floatType" />

    <objectAnimator
        android:duration="1000"
        android:propertyName="alpha"
        android:valueFrom="0"
        android:valueTo="1"
        android:valueType="floatType"/>

    <!--<objectAnimator-->
        <!--android:duration="1000"-->
        <!--android:propertyName="translationX"-->
        <!--android:valueFrom="100dp"-->
        <!--android:valueTo="0dp"-->
        <!--android:valueType="floatType" />-->

</set>
           

加載執行:

Animator animator = AnimatorInflater.loadAnimator(this,R.animator.animator1);
                animator.setTarget(imageView);
                animator.start();
           

仔細的看看xml代碼,其實沒有直接java建立動畫友善,java中屬性在一個動畫可以重複操作如:位置移動,從左到右,在到左。

3.實際應用

如果還需要其他的複雜效果就要通過我們自定義來實作了。比如網絡中的一些彈跳效果,水波效果等,這裡了解一些概念。

估值器:

所謂估值器從名稱上一直沒有了解明白。實際就是實作一個邏輯處理的方法。

估值器實作了一個接口重寫了evaluate()方法。

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);

}
           

看幾個個系統提供的估值器代碼:

public class IntEvaluator implements TypeEvaluator<Integer> {

    /**
     * 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 * (v1 - v0)</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; should be of type <code>int</code> or
     *                   <code>Integer</code>
     * @param endValue   The end value; should be of type <code>int</code> or <code>Integer</code>
     * @return A linear interpolation between the start and end values, given the
     *         <code>fraction</code> parameter.
     */
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
        int startInt = startValue;
        return (int)(startInt + fraction * (endValue - startInt));
    }
}
           

上面是一個整數估值器,evaluate();方法就是進行一個計算處理在傳回去。

public class PointFEvaluator implements TypeEvaluator<PointF> {

    private PointF mPoint;

    public PointFEvaluator() {
    }

    public PointFEvaluator(PointF reuse) {
        mPoint = reuse;
    }

    /**
     * This function returns the result of linearly interpolating the start and
     * end PointF values, with <code>fraction</code> representing the proportion
     * between the start and end values. The calculation is a simple parametric
     * calculation on each of the separate components in the PointF objects
     * (x, y).
     *
     * <p>If {@link #PointFEvaluator(android.graphics.PointF)} was used to construct
     * this PointFEvaluator, the object returned will be the <code>reuse</code>
     * passed into the constructor.</p>
     *
     * @param fraction   The fraction from the starting to the ending values
     * @param startValue The start PointF
     * @param endValue   The end PointF
     * @return A linear interpolation between the start and end values, given the
     *         <code>fraction</code> parameter.
     */
    @Override
    public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
        float x = startValue.x + (fraction * (endValue.x - startValue.x));
        float y = startValue.y + (fraction * (endValue.y - startValue.y));

        if (mPoint != null) {
            mPoint.set(x, y);
            return mPoint;
        } else {
            return new PointF(x, y);
        }
    }
}
           

PointFEvaluator 中evaluate()方法對兩個PointF進行處理,最後傳回。從上面看,估值器就是對指定的一些參數按照我們的需求,重新處理生成一個新的參數給動畫執行。

插值器:

估值器也是實作了一個接口和方法。

public interface TimeInterpolator {

    /**
     * Maps a value representing the elapsed fraction of an animation to a value that represents
     * the interpolated fraction. This interpolated value is then multiplied by the change in
     * value of an animation to derive the animated value at the current elapsed animation time.
     *
     * @param input A value between 0 and 1.0 indicating our current point
     *        in the animation where 0 represents the start and 1.0 represents
     *        the end
     * @return The interpolation value. This value can be more than 1.0 for
     *         interpolators which overshoot their targets, or less than 0 for
     *         interpolators that undershoot their targets.
     */
    float getInterpolation(float input);
}
           

系統提供了一些常用的插值器:

線性插值器,讓動畫成線性運動執行。對于接口的方法getInterpolation()直接傳回資料,沒有處理。

public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {

    public LinearInterpolator() {
    }

    public LinearInterpolator(Context context, AttributeSet attrs) {
    }

    public float getInterpolation(float input) {
        return input;
    }

    /** @hide */
    @Override
    public long createNativeInterpolator() {
        return NativeInterpolatorFactoryHelper.createLinearInterpolator();
    }
}
           

加速插值器,動畫逐漸加速。從代碼看,getInterpolation()方法傳回值是一個進行了乘法或者多次幂函數計算,從數學上說這就是一個幂函數曲線加速。

Math.pow(input, mDoubleFactor);

public class AccelerateInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
    private final float mFactor;
    private final double mDoubleFactor;

    public AccelerateInterpolator() {
        mFactor = 1.0f;
        mDoubleFactor = 2.0;
    }

    /**
     * Constructor
     *
     * @param factor 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) {
        this(context.getResources(), context.getTheme(), attrs);
    }

    /** @hide */
    public AccelerateInterpolator(Resources res, Theme theme, AttributeSet attrs) {
        TypedArray a;
        if (theme != null) {
            a = theme.obtainStyledAttributes(attrs, R.styleable.AccelerateInterpolator, 0, 0);
        } else {
            a = res.obtainAttributes(attrs, R.styleable.AccelerateInterpolator);
        }

        mFactor = a.getFloat(R.styleable.AccelerateInterpolator_factor, 1.0f);
        mDoubleFactor = 2 * mFactor;
        setChangingConfiguration(a.getChangingConfigurations());
        a.recycle();
    }

    public float getInterpolation(float input) {
        if (mFactor == 1.0f) {
            return input * input;
        } else {
            return (float)Math.pow(input, mDoubleFactor);
        }
    }

    /** @hide */
    @Override
    public long createNativeInterpolator() {
        return NativeInterpolatorFactoryHelper.createAccelerateInterpolator(mFactor);
    }
           

通過上述系統代碼的檢視我們大緻了解了,插值器就是通過一些數學計算,讓目前時間的動畫值改變,進而達到一定效果。

總的來說,估值器是處理了動畫目前的資料,而插值器就對目前執行速度操作,達到一定效果。後邊在對實際的自定義做練習。

參考資料:

http://www.jianshu.com/p/02deec7bf8f0

http://www.cnblogs.com/mengdd/p/3346003.html

繼續閱讀