安卓動畫使用小結

動畫的分類

總的來講,Android動畫能夠分爲兩類,最初的傳統動畫和Android3.0 以後出現的屬性動畫; 傳統動畫又包括 幀動畫(Frame Animation)和補間動畫(Tweened Animation)。java

幀動畫

幀動畫更多的依賴於完善的UI資源,他的原理就是將一張張單獨的圖片連貫的進行播放, 從而在視覺上產生一種動畫的效果;有點相似於某些軟件製做gif動畫的方式。android

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:drawable="@drawable/a_0"
        android:duration="100" />
    <item
        android:drawable="@drawable/a_1"
        android:duration="100" />
    <item
        android:drawable="@drawable/a_2"
        android:duration="100" />
</animation-list>

複製代碼
protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_frame_animation);
        ImageView animationImg1 = (ImageView) findViewById(R.id.animation1);
        animationImg1.setImageResource(R.drawable.frame_anim1);
        AnimationDrawable animationDrawable1 = (AnimationDrawable) animationImg1.getDrawable();
        animationDrawable1.start();
    }
複製代碼

把ui給的幀動畫的全部圖片按照順序卸載一個animation-list中,duration爲每一張圖片顯示的時間,推薦60便可,最後找到AnimationDrawable,調用strat方法就行,幀動畫不調用start方法只會顯示第一幀圖片,不會自動播放。git

注意: 幀動畫容易引發oom,因此幀動畫的全部圖片頭要進行壓縮,再放到工程中,而起儘可能不要有太多張數。推薦一個在線壓縮工具。TinyPNG,使用很是方便。程序員

補間動畫

補間動畫又能夠分爲四種形式,分別是 alpha(淡入淡出),translate(位移),scale(縮放大小),rotate(旋轉)。 補間動畫的實現,通常會採用xml 文件的形式;代碼會更容易書寫和閱讀,同時也更容易複用。github

XML 實現json

首先,在res/anim/ 文件夾下定義以下的動畫實現方式bash

alpha_anim.xml 動畫實現ide

<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:fromAlpha="1.0"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    android:toAlpha="0.0" />
複製代碼

scale.xml 動畫實現工具

<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:fromXScale="0.0"
    android:fromYScale="0.0"
    android:pivotX="50%"
    android:pivotY="50%"
    android:toXScale="1.0"
    android:toYScale="1.0"/>

複製代碼

而後,在Activity中oop

Animation animation = AnimationUtils.loadAnimation(mContext, R.anim.alpha_anim);
img = (ImageView) findViewById(R.id.img);
img.startAnimation(animation);
複製代碼

這樣就能夠實現ImageView alpha 透明變化的動畫效果。

也可使用set 標籤將多個動畫組合

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@[package:]anim/interpolator_resource"
    android:shareInterpolator=["true" | "false"] >
    <alpha
        android:fromAlpha="float"
        android:toAlpha="float" />
    <scale
        android:fromXScale="float"
        android:toXScale="float"
        android:fromYScale="float"
        android:toYScale="float"
        android:pivotX="float"
        android:pivotY="float" />
    <translate
        android:fromXDelta="float"
        android:toXDelta="float"
        android:fromYDelta="float"
        android:toYDelta="float" />
    <rotate
        android:fromDegrees="float"
        android:toDegrees="float"
        android:pivotX="float"
        android:pivotY="float" />
    <set>
        ...
    </set>
</set>

複製代碼

各個動畫屬性的含義結合動畫自身的特色應該很好理解,就不一一闡述了;這裏主要說一下interpolator 和 pivot。

Interpolator 主要做用是能夠控制動畫的變化速率 ,就是動畫進行的快慢節奏。Android 系統已經爲咱們提供了一些Interpolator ,好比 accelerate_decelerate_interpolator,accelerate_interpolator等。更多的interpolator 及其含義能夠在Android SDK 中查看。同時這個Interpolator也是能夠自定義的,這個後面還會提到。

pivot 決定了當前動畫執行的參考位置,pivot 這個屬性主要是在translate 和 scale 動畫中,這兩種動畫都牽扯到view 的「物理位置「發生變化,因此須要一個參考點。而pivotX和pivotY就共同決定了這個點;它的值能夠是float或者是百分比數值。

咱們以pivotX爲例:

pivotY 也是相同的原理,只不過變成的縱向的位置。

Java Code 實現

有時候,動畫的屬性值可能須要動態的調整,這個時候使用xml 就不合適了,須要使用java代碼實現

private void RotateAnimation() {
        animation = new RotateAnimation(-deValue, deValue, Animation.RELATIVE_TO_SELF,
                pxValue, Animation.RELATIVE_TO_SELF, pyValue);
        animation.setDuration(timeValue);

        if (keep.isChecked()) {
            animation.setFillAfter(true);
        } else {
            animation.setFillAfter(false);
        }
        if (loop.isChecked()) {
            animation.setRepeatCount(-1);
        } else {
            animation.setRepeatCount(0);
        }

        if (reverse.isChecked()) {
            animation.setRepeatMode(Animation.REVERSE);
        } else {
            animation.setRepeatMode(Animation.RESTART);
        }
        img.startAnimation(animation);
    }

複製代碼

這裏animation.setFillAfter決定了動畫在播放結束時是否保持最終的狀態;animation.setRepeatCount和animation.setRepeatMode 決定了動畫的重複次數及重複方式,具體細節可查看源碼理解。

屬性動畫

屬性動畫,顧名思義它是對於對象屬性的動畫。所以,全部補間動畫的內容,均可以經過屬性動畫實現。

屬性動畫入門

private void RotateAnimation() {
        ObjectAnimator anim = ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f);
        anim.setDuration(1000);
        anim.start();
    }

    private void AlpahAnimation() {
        ObjectAnimator anim = ObjectAnimator.ofFloat(myView, "alpha", 1.0f, 0.8f, 0.6f, 0.4f, 0.2f, 0.0f);
        anim.setRepeatCount(-1);
        anim.setRepeatMode(ObjectAnimator.REVERSE);
        anim.setDuration(2000);
        anim.start();
    }

複製代碼

這兩個方法用屬性動畫的方式分別實現了旋轉動畫和淡入淡出動畫,其中setDuration、setRepeatMode及setRepeatCount和補間動畫中的概念是同樣的。

能夠看到,屬性動畫貌似強大了許多,實現很方便,同時動畫可變化的值也有了更多的選擇,動畫所能呈現的細節也更多。

固然屬性動畫也是能夠組合實現的

ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(myView, "alpha", 1.0f, 0.5f, 0.8f, 1.0f);
                ObjectAnimator scaleXAnim = ObjectAnimator.ofFloat(myView, "scaleX", 0.0f, 1.0f);
                ObjectAnimator scaleYAnim = ObjectAnimator.ofFloat(myView, "scaleY", 0.0f, 2.0f);
                ObjectAnimator rotateAnim = ObjectAnimator.ofFloat(myView, "rotation", 0, 360);
                ObjectAnimator transXAnim = ObjectAnimator.ofFloat(myView, "translationX", 100, 400);
                ObjectAnimator transYAnim = ObjectAnimator.ofFloat(myView, "tranlsationY", 100, 750);
                AnimatorSet set = new AnimatorSet();
                set.playTogether(alphaAnim, scaleXAnim, scaleYAnim, rotateAnim, transXAnim, transYAnim);
//                set.playSequentially(alphaAnim, scaleXAnim, scaleYAnim, rotateAnim, transXAnim, transYAnim);
                set.setDuration(3000);
                set.start();

複製代碼

能夠看到這些動畫能夠同時播放,或者是按序播放。

屬性動畫——ValueAnimator

ValueAnimator是整個屬性動畫機制當中最核心的一個類,屬性動畫的運行機制是經過不斷地對值進行操做來實現的,而初始值和結束值之間的動畫過渡就是由ValueAnimator這個類來負責計算的。它的內部使用一種時間循環的機制來計算值與值之間的動畫過渡,咱們只須要將初始值和結束值提供給ValueAnimator,而且告訴它動畫所需運行的時長,那麼ValueAnimator就會自動幫咱們完成從初始值平滑地過渡到結束值這樣的效果。除此以外,ValueAnimator還負責管理動畫的播放次數、播放模式、以及對動畫設置監聽器等,確實是一個很是重要的類。

使用案列

ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);  
anim.setDuration(300);  
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {  
    @Override  
    public void onAnimationUpdate(ValueAnimator animation) {  
        float currentValue = (float) animation.getAnimatedValue();  
        Log.d("TAG", "cuurent value is " + currentValue);  
    }  
});  
anim.start();  
複製代碼

這個列子表明動畫從0到1動畫時長爲300毫秒,onAnimationUpdate方法中回調的是中間的變化數值,能夠基於這個變化值不停的改變view的屬性便可。

那麼除此以外,咱們還能夠調用setStartDelay()方法來設置動畫延遲播放的時間,調用setRepeatCount()和setRepeatMode()方法來設置動畫循環播放的次數以及循環播放的模式,循環模式包括RESTART和REVERSE兩種,分別表示從新播放和倒序播放的意思。這些方法都很簡單,我就再也不進行詳細講解了

屬性動畫——ObjectAnimator

相比於ValueAnimator,ObjectAnimator可能纔是咱們最常接觸到的類,由於ValueAnimator只不過是對值進行了一個平滑的動畫過渡,但咱們實際使用到這種功能的場景好像並很少。而ObjectAnimator則就不一樣了,它是能夠直接對任意對象的任意屬性進行動畫操做的,好比說View的alpha屬性。

例子:將一個TextView在5秒中內從常規變換成全透明,再從全透明變換成常規

ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);  
animator.setDuration(5000);  
animator.start(); 
複製代碼

將TextView進行一次360度的旋轉

ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f);  
animator.setDuration(5000);  
animator.start();  
複製代碼

第一個參數爲使用動畫的view,第二個爲動畫操做的屬性,後面的參數爲屬性的變化趨勢。

注意: 其實ObjectAnimator內部的工做機制並非直接對咱們傳入的屬性名進行操做的,而是會去尋找這個屬性名對應的get和set方法,若是沒有get和set方法,屬性動畫並不會起做用,不信能夠本身試試。

組合動畫——AnimatorSet

實現組合動畫功能主要須要藉助AnimatorSet這個類,這個類提供了一個play()方法,若是咱們向這個方法中傳入一個Animator對象(ValueAnimator或ObjectAnimator)將會返回一個AnimatorSet.Builder的實例,AnimatorSet.Builder中包括如下四個方法: after(Animator anim) 將現有動畫插入到傳入的動畫以後執行 after(long delay) 將現有動畫延遲指定毫秒後執行 before(Animator anim) 將現有動畫插入到傳入的動畫以前執行 with(Animator anim) 將現有動畫和傳入的動畫同時執行

例子:讓TextView先從屏幕外移動進屏幕,而後開始旋轉360度,旋轉的同時進行淡入淡出操做

ObjectAnimator moveIn = ObjectAnimator.ofFloat(textview, "translationX", -500f, 0f);  
ObjectAnimator rotate = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f);  
ObjectAnimator fadeInOut = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);  
AnimatorSet animSet = new AnimatorSet();  
animSet.play(rotate).with(fadeInOut).after(moveIn);  
animSet.setDuration(5000);  
animSet.start();  
複製代碼

Animator監聽器

在不少時候,咱們但願能夠監聽到動畫的各類事件,好比動畫什麼時候開始,什麼時候結束,而後在開始或者結束的時候去執行一些邏輯處理。這個功能是徹底能夠實現的,Animator類當中提供了一個addListener()方法,這個方法接收一個AnimatorListener,咱們只須要去實現這個AnimatorListener就能夠監聽動畫的各類事件了。

anim.addListener(new AnimatorListener() {  
    @Override  
    public void onAnimationStart(Animator animation) {  
    }  
  
    @Override  
    public void onAnimationRepeat(Animator animation) {  
    }  
  
    @Override  
    public void onAnimationEnd(Animator animation) {  
    }  
  
    @Override  
    public void onAnimationCancel(Animator animation) {  
    }  
});  
複製代碼

onAnimationStart()方法會在動畫開始的時候調用,onAnimationRepeat()方法會在動畫重複執行的時候調用,onAnimationEnd()方法會在動畫結束的時候調用,onAnimationCancel()方法會在動畫被取消的時候調用。

AnimatorListenerAdapter

使用這個類就能夠解決掉實現接口繁瑣的問題了,以下所示:

anim.addListener(new AnimatorListenerAdapter() {  
});  
複製代碼

這裏咱們向addListener()方法中傳入這個適配器對象,因爲AnimatorListenerAdapter中已經將每一個接口都實現好了,因此這裏不用實現任何一個方法也不會報錯。那麼若是我想監聽動畫結束這個事件,就只須要單獨重寫這一個方法就能夠了

ValueAnimator的高級用法——TypeEvaluator

那麼TypeEvaluator的做用究竟是什麼呢?簡單來講,就是告訴動畫系統如何從初始值過分到結束值。

實現位置1平滑過渡到位置2

來先定義一個Point類

public class Point {  
  
    private float x;  
  
    private float y;  
  
    public Point(float x, float y) {  
        this.x = x;  
        this.y = y;  
    }  
  
    public float getX() {  
        return x;  
    }  
  
    public float getY() {  
        return y;  
    }  
  
}  
複製代碼

接下來定義PointEvaluator

public class PointEvaluator implements TypeEvaluator{  
  
    @Override  
    public Object evaluate(float fraction, Object startValue, Object endValue) {  
        Point startPoint = (Point) startValue;  
        Point endPoint = (Point) endValue;  
        float x = startPoint.getX() + fraction * (endPoint.getX() - startPoint.getX());  
        float y = startPoint.getY() + fraction * (endPoint.getY() - startPoint.getY());  
        Point point = new Point(x, y);  
        return point;  
    }  
  
}  
複製代碼

PointEvaluator編寫完成了,接下來咱們就能夠很是輕鬆地對Point對象進行動畫操做了,好比說咱們有兩個Point對象,如今須要將Point1經過動畫平滑過分到Point2

Point point1 = new Point(0, 0);  
Point point2 = new Point(300, 300);  
ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), point1, point2);  
anim.setDuration(5000);  
anim.start();
複製代碼

注意:要能看到動畫效果,須要監聽動畫的變化過程,不停的變化值複製給view的屬性才行。

Interpolator的用法

Interpolator 被用來修飾動畫效果,定義動畫的變化率,可使存在的動畫效果accelerated(加速),decelerated(減速),repeated(重複),bounced(彈跳)等。

AccelerateDecelerateInterpolator 在動畫開始與結束的地方速率改變比較慢,在中間的時候加速 AccelerateInterpolator 在動畫開始的地方速率改變比較慢,而後開始加速 AnticipateInterpolator 開始的時候向後而後向前甩

AnticipateOvershootInterpolator 開始的時候向後而後向前甩必定值後返回最後的值 BounceInterpolator 動畫結束的時候彈起

CycleInterpolator 動畫循環播放特定的次數,速率改變沿着正弦曲線

DecelerateInterpolator 在動畫開始的地方快而後慢

LinearInterpolator 以常量速率改變

OvershootInterpolator 向前甩必定值後再回到原來位置

若是android定義的interpolators不符合你的效果也能夠自定義interpolators

使用以下:

anim.setInterpolator(new DecelerateAccelerateInterpolator());  
複製代碼

ViewPropertyAnimator的用法

ViewPropertyAnimator提供了更加易懂、更加面向對象的API,以下所示:

textview.animate().alpha(0f);  
複製代碼

果真很是簡單!不過textview.animate()這個方法是怎麼回事呢?animate()方法就是在Android 3.1系統上新增的一個方法,這個方法的返回值是一個ViewPropertyAnimator對象,也就是說拿到這個對象以後咱們就能夠調用它的各類方法來實現動畫效果了,這裏咱們調用了alpha()方法並轉入0,表示將當前的textview變成透明狀態。

怎麼樣?比起使用ObjectAnimator,ViewPropertyAnimator的用法明顯更加簡單易懂吧。除此以外,ViewPropertyAnimator還能夠很輕鬆地將多個動畫組合到一塊兒,好比咱們想要讓textview運動到500,500這個座標點上,就能夠這樣寫:

textview.animate().x(500).y(500);  
複製代碼

那麼怎樣去設定動畫的運行時長呢?很簡單,也是經過連綴的方式設定便可,好比咱們想要讓動畫運行5秒鐘,就能夠這樣寫:

textview.animate().x(500).y(500).setDuration(5000)  
        .setInterpolator(new BounceInterpolator());  
複製代碼

注意:

整個ViewPropertyAnimator的功能都是創建在View類新增的animate()方法之上的,這個方法會建立並返回一個ViewPropertyAnimator的實例,以後的調用的全部方法,設置的全部屬性都是經過這個實例完成的。 你們注意到,在使用ViewPropertyAnimator時,咱們自始至終沒有調用過start()方法,這是由於新的接口中使用了隱式啓動動畫的功能,只要咱們將動畫定義完成以後,動畫就會自動啓動。而且這個機制對於組合動畫也一樣有效,只要咱們不斷地連綴新的方法,那麼動畫就不會馬上執行,等到全部在ViewPropertyAnimator上設置的方法都執行完畢後,動畫就會自動啓動。固然若是不想使用這一默認機制的話,咱們也能夠顯式地調用start()方法來啓動動畫。 ViewPropertyAnimator的全部接口都是使用連綴的語法來設計的,每一個方法的返回值都是它自身的實例,所以調用完一個方法以後能夠直接連綴調用它的另外一個方法,這樣把全部的功能都串接起來,咱們甚至能夠僅經過一行代碼就完成任意複雜度的動畫功能。

lottie動畫

該動畫主要是靠ui設置師完成,經過安裝在AE上的一款名叫bodymovin的插件,可以將AE中的動畫工程文件轉換成通用的json格式描述文件,bodymovin插件自己是用於在網頁上呈現各類AE效果的一個開源庫,lottie作的事情就是實現了一個可以在不一樣移動端平臺上呈現AE動畫的方式.從而達到動畫文件的一次繪製、一次轉換、隨處可用的效果. 固然,就如Java一次編譯,隨處運行同樣,lottie自己這個動畫播放庫並非跨平臺的.

Lottie項目地址: github.com/airbnb/lott…

詳細使用請參考:www.jianshu.com/p/cae606f45…

總結:

對於屬性動畫的時候,最好寫成一個能複用的工具類,方便不一樣的地方使用。補間動畫雖然xml使用很方便,可是複用性很低,爲了項目長遠的發展,仍是應該作封裝處理,lottie動畫要看公司的選擇,這個動畫節約了程序員不少的時間,程序員能夠用更多的時間來作性能的調優和業務的優化。

相關文章
相關標籤/搜索