天天看點

Android 屬性動畫基礎使用

前言

Android3.0之前系統隻提供了補間動畫,但是它隻能針對View做動畫而且隻能在改變展示狀态無法整整的改變View的屬性值。比如補間動畫的偏移效果雖然View的位置在外觀上改變了,但實際的點選效果還需要在之前的位置點選才會回調。3.0之後提供的屬性動畫不但能夠對View做動畫還能夠對數值做動畫效果,所謂屬性動畫其實就是對具有get和set方法的屬性值做動畫效果,這樣不但是View的外觀發生變化還使得它的相關屬性值真正發生改變。

ValueAnimaor對象

ValueAnimator正如它的命名一樣它是針對值做動畫效果,比如Java中有常見的Integer/Float等數值,可以實作一個數值不停變化的動畫效果。

<?xml version="1.0" encoding="utf-8"?>
<animator xmlns:android="http://schemas.android.com/apk/res/android"
    android:valueType="intType"
    android:interpolator="@android:anim/accelerate_interpolator"
    android:duration="2000"
    android:valueFrom="0"
    android:valueTo="1000">
</animator>
           

在代碼中也可以直接定義屬性動畫,不過在XML中定義的便于複用,兩種寫法是等價的。

valueAnimation = (ValueAnimator) AnimatorInflater.loadAnimator(this, R.animator.value);
valueAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        textView.setText(String.valueOf(animation.getAnimatedValue()));
    }
});
valueAnimation.start();
           

開始動畫之後數值會一緻不停的增長直到最大值,效果如下:

Android 屬性動畫基礎使用

ValueAnimator是所有屬性動畫的最基礎實作,它隻能對數值類型的對象做動畫,如果需要對View等對象做屬性動畫可以使用它的子類ObjectAnimator來簡單實作。

ObjectAnimator對象

檢視ObjectAnimator的所有工廠方法接口主要有以下幾個初始化對象屬性動畫接口有很多中,這裡主要挑選幾個常用的屬性動畫接口來試用。

public static ObjectAnimator ofFloat(Object target, String propertyName, float... values)

public static ObjectAnimator ofArgb(Object target, String propertyName, int... values)

public static <T, V> ObjectAnimator ofObject(T target, @NonNull Property<T, V> property,
            @Nullable TypeConverter<PointF, V> converter, Path path)

public static ObjectAnimator ofPropertyValuesHolder(Object target,
PropertyValuesHolder... values)
           

ofFloat屬性動畫

補間動畫的内置四種動畫效果都可以使用這個屬性動畫來實作,因為View自帶了setAlpha/setRotate/setRotateX/setRotateY/setTranslationX/setTranslationY/scaleX/scaleY等多個屬性get/set方法。

<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:valueType="floatType"
    android:propertyName="alpha"
    android:duration="1000"
    android:valueFrom="1"
    android:valueTo="0.3">

</objectAnimator>

<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:valueFrom="0"
    android:valueTo="360"
    android:propertyName="rotation"
    android:valueType="floatType"
    android:duration="100"
    android:repeatCount="1">

</objectAnimator>

<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:valueFrom="0"
    android:valueTo="250"
    android:propertyName="translationX"
    android:valueType="floatType"
    android:duration="1000">

</objectAnimator>
           

這幾個動畫就實作了内置的補間動畫效果。

Android 屬性動畫基礎使用

這些動畫效果很容易實作是因為View自帶了這些屬性值,對于那些View不會自動維護的屬性值比如width需要使用包裝對象來實作屬性動畫效果。

// 包裝對象包含了width屬性,也就是實作了setWidth和getWidth
private static class ViewWrapper {
    private View view;
    public ViewWrapper(View view) {
        this.view = view;
    }

    public void setWidth(int width) {
        view.getLayoutParams().width = width;
        view.requestLayout();
    }

    public int getWidth() {
        return view.getLayoutParams().width;
    }
}

<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:valueFrom="350"
    android:valueTo="750"
    android:propertyName="width"
    android:valueType="intType"
    android:duration="1000">

</objectAnimator>

widthAnimation = AnimatorInflater.loadAnimator(this, R.animator.width);
widthAnimation.setTarget(new ViewWrapper(button));
widthAnimation.start();
           
Android 屬性動畫基礎使用

ofArgb動畫

這個動畫是專門針對顔色類型的值做動畫效果,比如常見的背景顔色動畫,執行過程中View的背景會随着時間流逝逐漸從一種顔色變換成另外一種新的顔色。

ObjectAnimator animator = ObjectAnimator.ofInt(button, "backgroundColor", Color.LTGRAY, Color.CYAN);
animator.setEvaluator(new ArgbEvaluator());
animator.start();
           

ofObject屬性動畫

這個Object指的是屬性是Object類型,比如前面的setWidth這個屬性的類型是Integer類型。View對象在展示的時候都有一個位置屬性,可以使用left和top屬性來标志,可以使用一個Position對象來儲存這兩個屬性值。

private static class Position {
    public float x;
    public float y;

    public Position(float x, float y) {
        this.x = x;
        this.y = y;
    }
}
           

但是在View裡并沒有setPosition和getPosition這個屬性的定義,直接繼承View來添加這兩個方法也不是一個好辦法,假如還需要為ImageView和TextView也添加這個屬性,那麼就需要再定義兩個子類分别繼承ImageView和TextView。屬性動畫提供了一Property這個接口來實作外加的屬性。

private static class PositionProperty extends Property<View, Position> {
    public PositionProperty(Class<Position> type, String name) {
        super(type, name);
    }

    @Override
    public Position get(View view) {
        return new Position(view.getX(), view.getY());
    }

    @Override
    public void set(View view, Position value) {
        view.setX(value.x);
        view.setY(value.y);
    }
}
           

這個接口的第一個泛型就是需要增加屬性的類,第二個參數則是添加的屬性類型,需要使用者實作get/set方法來實作屬性的綁定操作。

ObjectAnimator animator = ObjectAnimator.ofObject(image, new PositionProperty(Position.class, "position"), new PositionEvaluator(),
                    new Position(, ), new Position(, ), new Position(, ));
animator.setDuration();
animator.start();
           

ofObject接口添加了ImageView的position屬性動畫,由于屬性類型是Object類型需要使用者自己來做對象的值解析操作。

private static class PositionEvaluator implements TypeEvaluator<Position> {
    @Override
    public Position evaluate(float fraction, Position startValue, Position endValue) {
        // 計算Position随着時間流逝的屬性值變化
        float x = (endValue.x - startValue.x) * fraction + startValue.x;
        float y = (endValue.y - startValue.y) * fraction + startValue.y;
        return new Position(x, y);
    }
}
           

最終的實作效果如下:

Android 屬性動畫基礎使用

ofPropertyValuesHolder動畫

屬性值保持對象從命名上可以知道它是一個儲存屬性的多個值的容器,屬性動畫其實是一個過程使用者定義了它的開始和結束值中間的值都有屬性動畫架構來自動生成,所有這些值對應的中間狀态都會存放到PropertyValueHolder當中,如果屬性動畫需要同時做幾個屬性的動畫效果,可以将每個屬性都定義到一個PropertyValueHolder裡然後将它們統一放到ObjectAnimator對象裡,這樣就實作了同時做多個屬性動畫的功能。

PropertyValuesHolder translationX = PropertyValuesHolder.ofFloat("translationX", , );
PropertyValuesHolder translationY = PropertyValuesHolder.ofFloat("translationY", , );
PropertyValuesHolder rotationX = PropertyValuesHolder.ofFloat("rotationX", , );
PropertyValuesHolder rotationY = PropertyValuesHolder.ofFloat("rotationY", , );
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(button, translationX, translationY, rotationX, rotationY);

animator.setRepeatCount(ValueAnimator.INFINITE);
animator.setRepeatMode(ValueAnimator.REVERSE);
animator.start();
           

KeyFrame也就是通常所說的關鍵幀,實際上動畫執行時隻是生成關鍵的幀每個關鍵幀之間的幀都是計算機臨時生成的,PropertyValuesHolder裡存放的中間狀态就是這些關鍵幀,使用者也可以自定義關鍵幀将它們存儲在PropertyValuesHolder裡,實作的屬性動畫就會在這些關鍵幀中不停的做動畫。

Keyframe keyframe = Keyframe.ofFloat(, );
Keyframe keyframe1 = Keyframe.ofFloat(, -);
Keyframe keyframe2 = Keyframe.ofFloat(, );
Keyframe keyframe3 = Keyframe.ofFloat(, -);
Keyframe keyframe4 = Keyframe.ofFloat(, );
Keyframe keyframe5 = Keyframe.ofFloat(, -);
Keyframe keyframe6 = Keyframe.ofFloat(, );
Keyframe keyframe7 = Keyframe.ofFloat(, -);
Keyframe keyframe8 = Keyframe.ofFloat(, );
Keyframe keyframe9 = Keyframe.ofFloat(, -);
Keyframe keyframe10 = Keyframe.ofFloat(, );

PropertyValuesHolder propertyValuesHolder = PropertyValuesHolder.ofKeyframe("rotationX",
        keyframe, keyframe1, keyframe2, keyframe3, keyframe4,
        keyframe5, keyframe6, keyframe7, keyframe8, keyframe9, keyframe10);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(image, propertyValuesHolder);
animator.setDuration();
animator.start();
           

繼續閱讀