1. 程式人生 > >Android動畫-Property Animation(一)

Android動畫-Property Animation(一)

本章內容

在之前 《Android動畫-概述》中,我大概說了下Android Property Animation的由來,這裡就不做多介紹了,Property Animation 肯定不是一章就能講的完的,接下來的幾章都是建立在程式碼、效果圖的基礎上,介紹Property Animation的用法。
本章主要講的是 ObjectAnimator ,包括程式碼生成動畫,XML載入動畫。

簡述:在給出一大堆程式碼之前,先通過效果圖來看看一些有趣的動畫,通過一個簡單有趣的動畫逐步展開:

這裡寫圖片描述

這絕對是一個非常有趣的動畫,包含了 alpha、translationX、translationY、rotationX、rotationY、scaleX、scaleY , 一堆 Animation 名詞,在詳細看這個效果的程式碼之前,先了解一些重要的東西,有個印象就行,畢竟之後會很詳細的說明,擔心後面大家看的一頭霧水:

View Animation 和 Property Animation

alpha 依然不變

translate 分成了 translationX 和 translationY, 要想X軸、Y軸兩個一起變化就需要將 translationX 和 translationY 組合使用

rotate 分成了 rotation、rotationX、 rotationY,其中 rotation 和 rotate基本一致,都是圍繞某一箇中心旋轉,而 rotationX 和 rotationY 則應該算 Property Animation 帶來的新的效果,這兩種動畫分別表示著 X軸的立體動畫和Y軸的立體動畫。

scale 則分成了 scaleX 和 scaleY,和 translationX/Y 一樣,要想X軸、Y軸都有變化就必須一起使用

共同點:
duration 動畫時間
repeatCount 動畫重複次數
repeatMode 動畫重複模式
Interpolator 插值器

接下來,還需要看看3.0之後,View的變化

aplha:透明度,1是完全不透明,0是完全透明,這個也沒什麼好說的。

setTranslationX(floatX)、setTranslationY(floatY) 這兩個API的作用是對控制元件的位置進行調整,floatX 和 floatY 是一個相對值,相對於控制元件左上角原點的一個位移值。

setRotationX(floatX) 和 setRotationY(floatY) ,這兩個API分別代表著 改變與X軸平面的角度、改變與Y軸平面的角度,這話說的非常抽象,事實上這兩個API的效果也非常抽象,舉個栗子:把X軸、Y軸看成兩個垂直的平面,現在有一個ImageView 在畫面上,這個ImageView 現在肯定是與Y軸的平面平行,與X軸的平面垂直,如果我設定了 setRotationX(45),這個45代表的就是一個正45度角,那麼這個ImageView 就會變成一個底部向螢幕內延伸,傾斜的角度與X軸平面的角度成45度角,小角對著你。(感覺說完還是很抽象,下面會有效果,一會兒大家看看吧,事實上開發中,我基本沒有用到過,好奇葩的API)

setScaleX(floatX) 、setScaleY(floatY) 這個就簡單了,代表著 X軸方向的縮放,Y軸方向的縮放

setPivotX(floatX) 和 setPivotY(floatY):旋轉的軸點和縮放的基準點,預設是View的中心點。和View Animation 不一樣,Property Animation 提供的API和XML這兩種建立動畫的途徑中,都沒有額外的位置設定中心點,所以不管是 程式碼還是載入XML ,最後的中心點都是動畫控制元件本身在程式碼裡面去設定的。

setX(floatX) set(floatY) : 這個API是設定控制元件在螢幕上的絕對位置,這裡 floatX 和 floatY都是 絕對座標點

看完新的API,先貼一下上面那個 Set 動畫的程式碼,僅僅只是看上去,很多程式碼,其實就是一個方法:

public void set1(View view) {
        AnimatorSet set = new AnimatorSet();
        set.setDuration(3000);
        set.playTogether(
                ObjectAnimator.ofFloat(imageView, "alpha", 0.3f, 1f),
                ObjectAnimator.ofFloat(imageView, "scaleY", 0.1f, 1f),
                ObjectAnimator.ofFloat(imageView, "scaleX", 0.1f, 1f),
                ObjectAnimator.ofFloat(imageView, "rotationX", 0f, 360f),
                ObjectAnimator.ofFloat(imageView, "rotationY", 0f, 360f),
                ObjectAnimator.ofFloat(imageView, "translationY", 0f, -400f, 0f),
                ObjectAnimator.ofFloat(imageView, "translationX", 0f, -400f, 0f));
        set.start();
    }

AnimatorSet 作為 Property Animation 中的動畫集合,提供了多種動畫API,這裡用了

public void playTogether(Animator... items)

從方法名就可以看出這是一個一起動畫的API,引數是可變陣列,型別是 Animator,這是一個抽象類,所以我們要使用它的子類,ObjectAnimator的父類是ValueAnimator(Property Animation核心類,本章先不介紹它),ValueAnimator繼承於Animator,在 Property Animation 中做一些簡單的動畫,我一般都是用ObjectAnimator。
普通動畫APIpublic static ObjectAnimator ofFloat(Object target, String propertyName, float... values),tartget 毫無疑問是動畫控制元件,propertyName從上面的程式碼中可以看出,這個給定了你要制定的動畫型別,最後一個引數是一個可變陣列。這裡就可以看出Property Animation對於普通動畫,它需要的只是結果,也即是也想要這個動畫經歷什麼值,直接告訴API,然後其中實現、過渡這些都是不需要管的。

Alpha

這個是用程式碼實現的:

這裡寫圖片描述

public void alpha(View view) {
        ObjectAnimator anim = ObjectAnimator.ofFloat(imageView, "alpha", 1f,
                0.1f, 1f, 0.5f, 1f);
        anim.setDuration(5000);
        anim.start();
    }

這是一個最基本的透明漸變的動畫,我希望我的ImageView在5秒內的透明度 1f-0.1f-1f-0.5f-1f,然後接下來就和我沒有關係了。

接下來,讓我們來XML定義一個動畫,xml 定義路徑:res/animator

這裡寫圖片描述

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:ordering="sequentially">

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

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

    <objectAnimator
        android:duration="1400"
        android:propertyName="alpha"
        android:valueFrom="0.1"
        android:valueTo="0.8"
        android:valueType="floatType" />

</set>

很明顯一個objectAnimator節點是無法承載多個動畫的,必須使用set,在set下還需要指明它的子節點動畫是一起執行,還是按照XML順序依次執行。這裡android:ordering="sequentially"我規定是按照順序依次執行。還有一個值,規定一起執行的:android:ordering="together"
XML中 定義:第一,執行動畫的型別 android:propertyName,和 View Animation不一樣,View Animation 中一種動畫會有對應的節點,而Property Animation中所有基本動畫的節點都是objectAnimator,區別動畫的型別則是一個屬性:android:propertyName。比如 alpha :android:propertyName=”alpha”。第二,在Property Animation的XML中只有android:valueFrom=”0.1” 和 android:valueTo=”0.8” 這兩個動畫值得存在,不存在規定 scale動畫基點的屬性,以及規定 rotation 中心的屬性,這些都得去到java中呼叫對應控制元件的API去設定才成:setPivotX(floatX) 和 setPivotY(floatY)。
動態載入XML:

public void alpha(View view) {
//        Animator animator = AnimatorInflater.loadAnimator(this, R.animator.base_alpha_animator); // 簡單的透明動畫
        Animator animator = AnimatorInflater.loadAnimator(this, R.animator.base_set_alpha); // 複雜的透明動畫
        animator.setTarget(imageView);
        animator.start();
    }

這裡AnimatorInflater,就是一個用於動態載入的類。

scale

程式碼動畫:

這裡寫圖片描述

public void scale(View view) {
        ObjectAnimator anim = ObjectAnimator.ofFloat(imageView, "scaleX", 0.1f, 1f, 0.3f, 0.7f, 0.5f);
        imageView.setScaleY(2);
//        imageView.setScaleX(2);
        anim.setDuration(3000);
        anim.setRepeatCount(1);
        anim.setRepeatMode(ObjectAnimator.REVERSE);
        anim.start();
    }

這裡設定了repeatCount和repaeatMode給大家看看效果,順便測試了了一個View.setScaleY,效果很明顯 動畫順序反著又播了一遍,並且控制元件高度變成2倍。

XML

這裡寫圖片描述

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="3000"
    android:ordering="together">

    <set android:ordering="sequentially">
        <objectAnimator
            android:propertyName="scaleX"
            android:valueFrom="1"
            android:valueTo="1.5"
            android:valueType="floatType" />

        <objectAnimator
            android:propertyName="scaleX"
            android:valueFrom="1.5"
            android:valueTo="0.1"
            android:valueType="floatType" />
    </set>

    <set android:ordering="sequentially">
        <objectAnimator
            android:propertyName="scaleY"
            android:valueFrom="1"
            android:valueTo="0.1"
            android:valueType="floatType" />

        <objectAnimator
            android:propertyName="scaleY"
            android:valueFrom="0.1"
            android:valueTo="1.5"
            android:valueType="floatType" />
    </set>

</set>

正如之前說的,在Property Animation中如果想要X軸、Y軸一起變化,就需要同時使用scaleX、scaleY,在這個XML中我得想法是 把X軸的變化作為一個set,Y軸的變化是另一個set,它們的執行規定是依次執行,之後再把這兩個set一起執行。也就是 together下包含著兩個sequentially。其實另一種寫法可以是sequentially包含著兩個together,就是把某一階段X/Y軸的變化看成是一體的,然後一階段一階段的進行。

rotation

先看個最簡單的平面動畫

這裡寫圖片描述

 public void rotate(View view) {
//        ObjectAnimator anim = ObjectAnimator.ofFloat(imageView, "rotationY", 0f, 360f, 200f, 315f, 225f, 269f);  這是個逗逼的動畫
        ObjectAnimator anim = ObjectAnimator.ofFloat(imageView, "rotation", 0f, 720f);
//        imageView.setRotationX(-45);
//        imageView.setRotationY(-30);
        imageView.setPivotX(-100f);
        imageView.setPivotY(-100f);
        anim.setDuration(5000);
        anim.setInterpolator(new AccelerateInterpolator());
        anim.start();
    }

這是一個非常簡單的動畫,其實就是在模擬View Animation 中的rotate,這裡如果不設定imageView.setPivotX(-100f); imageView.setPivotY(-100f);那麼它的預設旋轉中心就是ImageView本身的中心點,需要說的是,這裡的imageView.setPivotX(-100f);
imageView.setPivotY(-100f)都是相對於控制元件左上角的相對位置;並且這裡使用了 加速 的插值器。

3D動畫

這裡寫圖片描述

    public void rotate(View view) {
//        ObjectAnimator anim = ObjectAnimator.ofFloat(imageView, "rotationY", 0f, 360f, 200f, 315f, 225f, 269f);  這是個逗逼的動畫
        ObjectAnimator anim = ObjectAnimator.ofFloat(imageView, "rotationY", 0f, 720f);
//        imageView.setRotationX(-45);
//        imageView.setRotationY(-30);
        imageView.setPivotX(-100f);
        imageView.setPivotY(-100f);
        anim.setDuration(5000);
        anim.setInterpolator(new AccelerateInterpolator());
        anim.start();
    }

rotationY就是圍繞中心點做的Y軸方向的3D動畫,如果你想看X軸方向,換成rotationX就OK了。

傾斜旋轉動畫

這裡寫圖片描述

    public void rotate(View view) {
//        ObjectAnimator anim = ObjectAnimator.ofFloat(imageView, "rotationY", 0f, 360f, 200f, 315f, 225f, 269f);  這是個逗逼的動畫
        ObjectAnimator anim = ObjectAnimator.ofFloat(imageView, "rotation", 0f, 720f);
        imageView.setRotationX(-45);
//        imageView.setRotationY(-30);
//        imageView.setPivotX(-100f);
//        imageView.setPivotY(-100f);
        anim.setDuration(5000);
        anim.setInterpolator(new AccelerateInterpolator());
        anim.start();
    }

imageView.setRotationX(-45) 這個API表示著,ImageView底部向螢幕內側傾斜45°,也就是ImageVIew和X軸平面的相交,角度從90°,變成45°,就變成上圖中的效果。

XML

這裡寫圖片描述

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:ordering="sequentially">

    <objectAnimator
        android:duration="1500"
        android:propertyName="rotation"
        android:valueFrom="0"
        android:valueTo="28"
        android:valueType="floatType" />


    <objectAnimator
        android:duration="1500"
        android:propertyName="rotationX"
        android:valueFrom="0"
        android:valueTo="360"
        android:valueType="floatType" />

</set>
   public void rotate(View view) {
//        Animator animator = AnimatorInflater.loadAnimator(this, R.animator.base_rotation_animator); //簡單的旋轉動畫
        Animator animator = AnimatorInflater.loadAnimator(this, R.animator.base_set_rotate);
        animator.setTarget(imageView);
        imageView.setPivotX(imageView_height);
        imageView.setPivotY(0);
        animator.start();
    }

這個旋轉動畫是先正方向旋轉28°,將對角線與X軸平行,然後在程式碼裡面將對角線上的點作為中心點旋轉,其實也就是繞著對角線旋轉

translation

這裡寫圖片描述

public void translate(View view) {
        imageView.setTranslationX(-200);
        ObjectAnimator anim = ObjectAnimator.ofFloat(imageView, "translationY", 0f, -400f, 0f);
        anim.setDuration(3000);
        anim.start();
    }

以控制元件左上角為原點位移-200px imageView.setTranslationX(-200),然後translationY,從0位移-400,最後在回到Y軸的原點。


XML

這裡寫圖片描述

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="3000"
    android:ordering="together">

    <set android:ordering="sequentially">

        <objectAnimator
            android:propertyName="translationX"
            android:valueFrom="-150"
            android:valueTo="0" />

    </set>

    <set android:ordering="sequentially">

        <objectAnimator
            android:propertyName="translationY"
            android:valueFrom="-200"
            android:valueTo="0" />

        <objectAnimator
            android:interpolator="@android:anim/bounce_interpolator"
            android:propertyName="translationY"
            android:valueFrom="0"
            android:valueTo="100" />

    </set>

</set>

回彈的效果看不到也是沒轍。

拋物線

這裡寫圖片描述

private float setX = 0;

    public void setXY(View view) {
        imageView.setScaleX(0.1f);
        imageView.setScaleY(0.1f);
        setX = 0;
        ObjectAnimator anim = ObjectAnimator.ofFloat(imageView, "cjh", 0f, 1f);
        anim.setDuration(3000);
        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float value = (Float) animation.getAnimatedValue();//得到動畫變化的屬性值
                setX = 400 * value;
                float setY = -1 / 75 * setX * setX + 4 * setX;
                imageView.setX(setX);
                imageView.setY(setY);
            }
        });
        anim.start();
    }

事實上,Property Animation 是可以拿到時間值然後自定義動畫效果,程式碼中,我定義我要從 0 - 1,但是具體做什麼我隨便寫的,然後在重新整理監聽裡面,呼叫了拋物線的公式,然後 setX setY,不斷更新ImageView的位置

至此,關於 Proerty Animation 的基本使用都講完了,主要是詳細的講了 ObjectAnimator 的使用和XML的寫法,接下來就是更為重要的動畫了。

原始碼下載