Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android動畫之屬性動畫(上)

Android動畫之屬性動畫(上)

編輯:關於Android編程

前言

在前面的文章中我們講述了Android動畫之視圖動畫學習了怎麼對一個view實現動畫,可以實現動畫包括平移,旋轉,縮放,漸變和幀動畫,這一篇我們來學習一個新的動畫實現方式。

屬性動畫

為什麼需要屬性動畫?

Android在3.0引入了屬性動畫,既然之前已經有屬性動畫了,為什麼還要引入屬性動畫吶?視圖動畫不好用嗎?還是視圖動畫不能夠實現功能?隨著系統的迭代更新,和設計的發展,以前做app都是比較簡單的,但是現在的app越來越復雜,功能越來越多,動畫效果也更加的復雜,更阿基要求實時性和界面的絢麗,因此老的系統很多實現都已經改變,對新的功能也力不從心,所以才引入屬性動畫來改善動畫的效果, 主要有如下原因:

1,視圖動畫是非交互動畫,僅僅只是改變了顯示位置
2,視圖動畫種類有限,復雜的效果力不從心
3,視圖動畫調用onDraw來重繪界面,耗費資源
4,視圖動畫只能針對view實現動畫,對非view不能實現

我們分別解釋一下上面的四點:

視圖動畫是非交互動畫,僅僅只是改變了顯示位置

我們在上一章講述了視圖動畫是非交互動畫,這個雖然不是一個很大的缺陷,但是在真的需要交互的時候就力不從心了,要實現額外的代碼才能實現其效果,

視圖動畫種類有限,復雜的效果力不從心

其次在現階段很多app都有非常復雜的效果,僅僅依靠視圖動畫的組合往往很難實現,就算實現了效果,代碼也非常的多,可能難以維護。

視圖動畫調用onDraw來重繪界面,耗費資源

onDraw來返回重繪界面,這樣就導致耗費資源和性能,流暢性是一個app非常重要的體驗,雖然單一一個動畫不能特別明顯的拖慢性能,但是各個地方差值綜合就會導致體驗很差

視圖動畫只能針對view實現動畫,對非view不能實現

視圖動畫的種類僅僅只有四種,並且只能針對view實現,如果只是針對一個view的背景顏色,或者其他的屬性來實現動畫,就不能實現。

屬性動畫的特點

我們在上面大書特書了視圖動畫的不足,那是不是屬性動畫就完全彌補了視圖動畫的不足?答案是的:

1,屬性動畫真正改變的是對象的屬性
2,屬性動畫是可以交互的
3,屬性動畫針對view與非view都能實現動畫
4,如果屬性不存在,還可以自定義屬性來實現動畫

視圖動畫的使用場景

雖然屬性動畫有這樣那樣的優點,是不是視圖動畫我們就拋諸腦後,不在使用?是,也不是?如果你新開發一個app,並且不是支持3.0一下的版本,那最好是直接使用屬性動畫,那什麼時候使用視圖動畫?

1,現有代碼已經實現效果
2,視圖動畫能實現所需要的效果
3,視圖動畫只需要更少的代碼來實現

代碼結構

Animator
ValueAnimator
ObjectAnimator TimeAnimator AnimatorSet

這裡我們主要注意一下視圖動畫與屬性動畫的異同。代碼結構很類似,但是根節點是不一樣的,視圖動是Animation,屬性動畫是Animator,視圖動畫有四個子類,平移,旋轉,縮放,漸變,這裡完全用ObjectAnimator來代替了。

動畫實現方式

xml實現

在res/animator下定義動畫文件(ValueAnimator-animator,ObjectAnimator
–objectAnimator, AnimatorSet-set ) 代碼中采用AnimatorInflater().
loadAnimator()加載

代碼實現

采用ObjectAnimator或者ValueAnimator實現

動畫實現

ObjectAnimator

我們上面講述了兩種動畫的實現方式。這裡我們先講述一下代碼實現,我們先來看看在視圖動畫的一個截圖,當時實現了平移,旋轉,縮放,漸變,那這裡我們用屬性動畫來實現一遍:

這裡寫圖片描述vcq9o6zO0sPHz8jAtL+0v7S/ydLUyrnTw7XEYXBp09DExNCpo788L3A+DQo8cD48aW1nIGFsdD0="這裡寫圖片描述" src="/uploadfile/Collfiles/20161004/20161004090051479.jpg" title="\" />

我們從圖片可以到,of類型的函數有很多種,有ofArgb,ofFloat,ofInt等,這裡有這麼多api,那我們使用哪一個?這裡我們主要使用ofFloat,因為這個函數是從3.0引入的,這個函數比較通用,其他的函數有的是4.0引入的,5.0引入的。因此這裡我們主要講解ofFloat:

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

各個屬性的解釋如下:

1,target作用的對象
2,propertyName作用的屬性,需要有public的setName函數
3,values可變參數,表示動畫執行的一組值

漸變

private void alpha() {
    ObjectAnimator alpha = ObjectAnimator.ofFloat(love, "alpha", 1.0f, 0.0f);
    alpha.setDuration(1000);
    alpha.start();
}

這裡使用的屬性是alpha,1.0f表示完全不透明,0.0f表示完全透明。

平移

private void translate() {
    ObjectAnimator translate = ObjectAnimator.ofFloat(love, "translationX", 200f);
    translate.setDuration(1000);
    translate.start();
}

這裡使用的是translationX屬性,只平移了x軸,Y軸不做變化。

縮放

private void scale() {
ObjectAnimator scaleX = ObjectAnimator.ofFloat(love, “scaleX”, 1.0f, 2.0f);
scaleX.setDuration(1000);
scaleX.start();
ObjectAnimator scaleY = ObjectAnimator.ofFloat(love, “scaleY”, 1.0f, 2.0f);
scaleY.setDuration(1000);
scaleY.start();
}
這裡使用了scaleX與scaleY屬性,1.0f表示原始大小,2.0f表示放大一倍。默認縮放為中心縮放。
旋轉

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

這裡使用的是rotation屬性,旋轉了360度,默認的旋轉中心為視圖中心。

上面我使用了一系列屬性,我怎麼知道哪些屬性可以用哪些屬性不能用。這裡我們去查找對應view所包含的屬性就知道了。

沒有對應屬性

上面我們都是使用已知的屬性,如果一個view我們想要實現的效果沒有對應的屬性怎麼辦?

直接添加set函數
包裝原有類,添加set函數
采用ValueAnimator實現

這裡我們解釋以下上面的情況,第一種如果你有權限,或者是自定義的view,如果沒有對應屬性,我們可以手動添加對應的屬性,第二種情況,我們可以包裝現有類,添加對應的屬性,第三種我們可以采用ValueAnimator來實現,這裡我們來包裝一下原有類,後面我們會講解ValueAnimator的實現。

我們就以上述縮放效果來演示,上面我們使用了兩個屬性scaleX,scaleY來縮放一個view,這裡我們用一個屬性scale屬性來縮放,但是ImageView沒有縮放這個屬性,那怎麼辦?

public class WrapperView {

    public ImageView target;

    private float scale;

    public WrapperView(ImageView target) {
        this.target = target;
    }

    public float getScale() {
        return scale;
    }

    public void setScale(float scale) {
        this.scale = scale;
        target.setScaleX(scale);
        target.setScaleY(scale);
    }
}

我們包裝對應的imageview,給他添加對應的scale屬性,之後在代碼中使用。動畫代碼如下:

private void addProperty() {

    WrapperView view = new WrapperView(love);
    ObjectAnimator scale = ObjectAnimator.ofFloat(view, "scale", 1.0f, 2.0f);
    scale.setDuration(1000);
    scale.start();
}

這裡我們使用的屬性就是上述添加的scale屬性。這樣我們就實現了縮放的效果。

組合動畫

我們在視圖動畫時講過,動畫有並行,串行,屬性動畫也有這些組合。那我們接下來就講述一下這些效果。

並行動畫

並行動畫,就是說多個動畫同時執行,比如我們在旋轉的同時縮放一個view,這裡主要有三種方式實現:

1:多個ObjectAnimator實現

private void togetherAnim1() {
    ObjectAnimator rotate = ObjectAnimator.ofFloat(love, "rotation", 0f, 360f).setDuration(1000);
    ObjectAnimator scaleX = ObjectAnimator.ofFloat(love, "scaleX", 1.0f, 2.0f).setDuration(1000);
    ObjectAnimator scaleY = ObjectAnimator.ofFloat(love, "scaleY", 1.0f, 2.0f).setDuration(1000);
//        rotate.start();
//        scaleX.start();
//        scaleY.start();
    AnimatorSet set = new AnimatorSet();
    set.playTogether(rotate, scaleX, scaleY);
    set.setDuration(1000);
    set.start();
}

這裡我們定義了三個ObjectAnimator,之後用AnimatiorSet來進行執行。調用playTogether來同時執行這個三個動畫,還有一種方式是,可以分別start三個動畫也能實現效果。

這裡有人可能會有疑問,連續三個start那不應該是串行的嗎?怎麼會是並行的吶?其實這裡的start,動畫並沒有立即開始執行,而是等待下一個刷新時間戳過來才執行的。

2:一個ObjectAnimator實現

private void togetherAnim2() {
    PropertyValuesHolder rotate = PropertyValuesHolder.ofFloat("rotation", 0f, 360f);
    PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 1.0f, 2.0f);
    PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 1.0f, 2.0f);
    ObjectAnimator together = ObjectAnimator.ofPropertyValuesHolder(love, rotate, scaleX, scaleY);
    together.setDuration(1000);
    together.start();
}

這裡我們使用PropertyValuesHolder來實現,定義三個PropertyValuesHolder,它與ObjectAnimator的區別是沒有target屬性,之後將PropertyValuesHolder放置到ObjectAnimator裡面,之後start ObjectAnimator動畫。

3:采用ViewPropertyAnimator實現

private void togetherAnim3() {
    love.animate().rotation(360f).scaleX(2.0f).scaleY(2.0f).setDuration(1000).start();
}

該方式系統已經實現了一個幫助方法,animate,之後可以鏈式的執行各個屬性。該方式代碼量是最少了的。

串行動畫

前面已經實現了並行,我們調用了playTogether,這裡我們只要換成另外一種方法就可以實現串行。

private void sequenceAnim() {
    ObjectAnimator rotate = ObjectAnimator.ofFloat(love, "rotation", 0f, 360f).setDuration(1000);
    ObjectAnimator scaleX = ObjectAnimator.ofFloat(love, "scaleX", 1.0f, 2.0f).setDuration(1000);
    ObjectAnimator scaleY = ObjectAnimator.ofFloat(love, "scaleY", 1.0f, 2.0f).setDuration(1000);
    AnimatorSet set = new AnimatorSet();
    set.playSequentially(rotate, scaleX, scaleY);
    set.setDuration(1000);
    set.start();
}

只需要將playTogether換成為playSequentially就可以了。

排列多個動畫

前面我們實現了並行與串行動畫,但是如果一個動畫既有串行又有並行怎麼辦?代碼如下:

private void compositeAnim() {
    ObjectAnimator translateY = ObjectAnimator.ofFloat(love, "translationY", -200f).setDuration(1000);
    ObjectAnimator scaleX = ObjectAnimator.ofFloat(love, "scaleX", 1.0f, 2.0f).setDuration(1000);
    ObjectAnimator scaleY = ObjectAnimator.ofFloat(love, "scaleY", 1.0f, 2.0f).setDuration(1000);
    ObjectAnimator rotate = ObjectAnimator.ofFloat(love, "rotation", 0f, -45f).setDuration(1000);
    AnimatorSet set = new AnimatorSet();
    set.play(scaleX).with(scaleY).with(rotate);
    set.play(translateY).after(scaleX);
    set.start();
}

這裡還是采用AnimatorSet來實現,with表示同時執行動畫。before方法,before裡面的代碼後執行,after方法,after裡面的動畫先執行。

ValueAnimator

前面我們已經講解了ObjectAnimator,我們前面的代碼結構中還有ValueAnimator,那ValueAnimator是什麼吶?

1,ValueAnimator是一個數值發生器
2,ValueAnimator不作用於任何屬性
3,需要在onAnimationUpdate獲取當前時間點發生的值

我們解釋一下上面的要點,首先ValueAnimator是一個數值發生器,就是他只產生數值,不對任何屬性起作用,因此他與ObjectAnimator不同,他不能產生動畫,動畫需要我們手動來處理。處理的方式就是在onAnimationUpdate中獲取產生的值。

那我們就來用ValueAnimator來實現一個動畫,我們實現一個倒計時的動畫:

private void countDown() {
    ValueAnimator countDown = ValueAnimator.ofInt(10, 0);
    countDown.setDuration(10000);
    countDown.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            textView.setText("" + animation.getAnimatedValue());
        }
    });
    countDown.start();
}

這裡我們用的ofInt函數,因為倒計時是整數,所以這裡用ofInt,我們在對動畫設置執行時長,最後在回調中獲取產生的值,animation.getAnimatedValue()就是當前產生的值。我們使用這個產生的值,實現倒計時動畫效果。

動畫監聽

我們已經學習了怎麼用ObjectAnimator和ValueAnimator來處理動畫,但是如果需要監聽動畫的開始和結束又怎麼辦?
我們可以添加監聽:

private void alpha() {
    ObjectAnimator alpha = ObjectAnimator.ofFloat(love, "alpha", 1.0f, 0.0f);
    alpha.setDuration(1000);
    alpha.addListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animation) {
            Toast.makeText(ObjectAnimationActivity.this, "start", Toast.LENGTH_LONG).show();
            ;
        }

        @Override
        public void onAnimationEnd(Animator animation) {

        }

        @Override
        public void onAnimationCancel(Animator animation) {

        }

        @Override
        public void onAnimationRepeat(Animator animation) {

        }
    });
    alpha.start();
}

我們可以對動畫添加Animator.AnimatorListener監聽,有四個回調函數,這樣我們就可以在動畫開始,結束進行處理。

不過上訴有四個回調,我們往往是不需要處理這麼多回調,僅僅只是想處理需要關注的回調,這種情況有解嗎?我們可以采用如下的方式進行處理:

private void translate() {
    ObjectAnimator translate = ObjectAnimator.ofFloat(love, "translationX", 200f);
    translate.setDuration(1000);
    translate.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
            super.onAnimationEnd(animation);
            //TODO
        }
    });
    translate.start();
}

對動畫設置AnimatorListenerAdapter,這裡我們只需要關注需要關注的回調。

還有一種監聽方式我們前面已經使用過了。就是ValueAnimator中添加監聽,我們可以添加ValueAnimator.AnimatorUpdateListener監聽,在onAnimationUpdate回調中進行處理。

插值器

在視圖動畫中,我們已經講解過插值器,這裡的插值器與視圖動畫中的插值器沒有什麼區別。因此就不在進行講述了。

總結

這裡我們已經講述完成了屬性動畫的實現,還有其他的屬性沒有實現,在接下來的一篇中我們繼續講述剩下的屬性。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved