進階之路 | 奇妙的Animation之旅

前言

本文已經收錄到個人Github我的博客,歡迎大佬們光臨寒舍:php

個人GIthub博客html

學習清單:

  • 動畫的種類
  • 自定義View動畫
  • View動畫的特殊使用場景
  • 屬性動畫
  • 使用動畫的注意事項

一.爲何要學習Animation?

筆者在以前進階之路 | 奇妙的View之旅中,說起View滑動的七種方式的時候簡單說到Animation,想必看過的讀者們已經對Animation有一個簡單的印象。java

動畫,對於一個APP來講很是重要,如今市面上使用的用戶比較多的APP,無一不是採用了各類豐富多彩的動畫效果;在應用中善於使用動畫,不只讓APP的體驗更上一層樓,還能緊緊抓住用戶的心!android

而做爲開發者的咱們,必定要對動畫有必定深度的瞭解,在平常的學習或者工做中多多嘗試動畫,以提升應用程序的美觀度和易用性!git

什麼,你不信動畫很重要....反手甩你一個對比視頻:過渡動畫有多重要?github

動畫的分類

二.核心知識點概括

2.1 View動畫

View動畫(視圖動畫)分爲兩部分:bash

  • 補間動畫
  • 幀動畫

2.1.1 補間動畫

1 基礎知識

Q1:主要的變換效果app

名稱 標籤 子類 效果
平移動畫 translate TranslateAnimation 移動View
縮放動畫 scale ScaleAnimation 放大或縮小View
旋轉動畫 rotate RotateAnimation 旋轉View
透明度動畫 alpha AlphaAnimation 改變View的透明度

注意:View動畫的View移動只是視覺效果,並不能真正的改變view的位置。dom

Q2:動畫的建立ide

對於View動畫建議採用XML來定義,由於XML可讀性更好

建立方法一:經過XML定義

  • XML文件建立在res/anim/
  • 根節點set,子節點translatescalerotatealpha,分別對應四種View動畫:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="true" android:fillAfter="true">
    
    <translate android:fromXDelta="float" android:toXDelta="float" android:fromYDelta="float" android:toYDelta="float"/>
     <scale android:fromXScale="float" android:toXScale="float" android:fromYScale="float" android:toYScale="float" android:pivotX="float" android:pivotY="float"/>    
     <rotate android:fromDegrees="float" android:toDegrees="float" android:pivotY="float" android:pivotX="float"/>
    <alpha android:fromAlpha="float" android:toAlpha="float"/>

</set>
複製代碼

接下來分別解釋各個節點下屬性含義:

A.set:表示動畫集合,對應AnimationSet

  • interpolator:表示動畫集合所採用的插值器,影響動畫的速度。能夠不指定,默認是accelerate_decelerate_interpolate(加速減速插值器)。下文會詳細介紹插值器的相關知識。
  • shareInterpolator:表示集合中的動畫是否和集合共享一個插值器。若是集合不指定插值器, 那麼子動畫就須要單獨制定所需的插值器或者使用默認值。
  • fillAfter:表示動畫結束時是否保持動畫結束時的狀態

B.translate:表示平移動畫,對應TranslateAnimation

  • android:fromXDelta:動畫起始時X座標上的位置。
  • android:toXDelta:動畫結束時X座標上的位置。
  • android:fromYDelta:動畫起始時Y座標上的位置。
  • android:toYDelta:動畫結束時Y座標上的位置。

注意:以上四個屬性以及後面幾個相似屬性的取值多是數值、百分數、百分數p,各自含義是:

  • 50:以View左上角爲原點沿座標軸正方向偏移50px。
  • 50%:以View左上角爲原點沿座標軸正方向偏移View寬/高度的50%。
  • 50%p:以View左上角爲原點沿座標軸正方向偏移父(parent)控件寬/高度的50%。區別如圖:

各類偏移屬性取值的區別

C.scale:表示縮放動畫,對應ScaleAnimation

  • fromXScale:動畫起始時X座標上的伸縮尺寸
  • toXScale:動畫結束時X座標上的伸縮尺寸
  • fromYScale:動畫起始時Y座標上的伸縮尺寸
  • toYScale:屬性爲動畫結束時Y座標上的伸縮尺寸

以上四個屬性值的值含義:

  • 值=0.0 :表示收縮到沒有

  • 值<1.0 :表示收縮

  • 值=1.0 :表示無伸縮

  • 值>1.0 :表示放大

  • pivotX:動畫相對於物件的X座標的開始位置
  • pivotY:動畫相對於物件的Y座標的開始位置

以上兩個屬性值表示縮放的軸點:從0%-100%中取值。

D.rotate:表示旋轉動畫,對應RotateAnimation類。

  • fromDegrees:動畫起始時物件的角度 (0度指X軸正方向所在方向)
  • toDegrees:動畫結束時物件旋轉的角度

以上兩個屬性共同肯定旋轉方向,原則是:當角度(to-from)爲數時表示逆時針旋轉,反之。

  • pivotY:動畫旋轉的軸點的X座標
  • pivotX:動畫旋轉的軸點的Y座標

E.alpha:表示透明度動畫,對應AlphaAnimation

  • fromAlpha:動畫起始時透明度
  • toAlpha:動畫結束時透明度

以上兩個屬性值:從0-1中取值。注意:

  • 值=0.0 :表示徹底透明
  • 值=1.0 :表示徹底不透明

以上四類補間動畫除了各自的特有屬性外,它們的共有屬性有:

共有屬性

xml聲明好以後,接下來只要在代碼中startAnimation(animation)開始動畫便可,代碼以下:

Animation animation = AnimationUtils.loadAnimation(this, R.anim.XXX);
mView.startAnimation(animation);
複製代碼

同時,可經過Animation的setAnimationListener(new AnimationListener(){...})給動畫添加過程監聽,這樣在動畫開始、結束和每一次循環時均可在回調方法中監聽到。接口代碼以下:

public static interface AnimationListener {
        //動畫開始 
        void onAnimationStart(Animator animation);
        //動畫結束
        void onAnimationEnd(Animator animation);
        //動畫重複
        void onAnimationRepeat(Animator animation);
    }
複製代碼

建立方法二: 經過Java代碼動態建立

  • 具體步驟:
    1. 建立TranslateAnimationRotateAnimationScaleAnimationAlphaAnimation對象。
    2. 設置建立的動畫對象的屬性,如動畫執行時間、延遲時間、起始位置、結束位置等
    3. 經過View.startAnimation()方法開啓動畫
    4. 可經過Animation.setAnimationListener()設置動畫的監聽器

Q3:綜合實例

A1:平移

//法一:xml定義
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="2000" android:fromXDelta="0" android:fromYDelta="0" android:toXDelta="100%" android:toYDelta="100%">
</translate>

//在MainActivity中調用
  Animation translateAnim = AnimationUtils.loadAnimation(this, R.anim.view_anim_translate);
    mImageView.startAnimation(translateAnim);
複製代碼
//法二:java代碼建立 RELATIVE_TO_SELF表示相對自身View
TranslateAnimation translateAnimation = new TranslateAnimation(
            Animation.RELATIVE_TO_SELF, 0,
            Animation.RELATIVE_TO_SELF, 1,
            Animation.RELATIVE_TO_SELF, 0,
            Animation.RELATIVE_TO_SELF, 1);
    translateAnimation.setDuration(2000);
    mImageView.startAnimation(translateAnimation);
}
複製代碼

平移效果

A2:縮放

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

//在MainActivity中調用
   Animation scaleAnim = AnimationUtils.loadAnimation(this, R.anim.view_anim_scale);
    mImage.startAnimation(scaleAnim);
複製代碼
//法二:java代碼建立
ScaleAnimation scaleAnimation = new ScaleAnimation(
            1, 0.5f,
            1, 0.5f,
            Animation.RELATIVE_TO_SELF, 0.5f,
            Animation.RELATIVE_TO_SELF, 0.5f);
    scaleAnimation.setDuration(2000);
    mImageView.startAnimation(scaleAnimation);
複製代碼

縮放效果

A3: 旋轉

//法一:xml定義
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="2000" android:fillAfter="true" android:fromDegrees="0" android:toDegrees="360" android:pivotX="50%" android:pivotY="50%">
</rotate>

//在MainActivity中調用
Animation rotateAnim = AnimationUtils.loadAnimation(this, R.anim.view_anim_rotate);
    mImageView.startAnimation(rotateAnim);
複製代碼
//法二:java代碼建立
RotateAnimation rotateAnimation = new RotateAnimation(
            0, 360,
            Animation.RELATIVE_TO_SELF, 0.5f,
            Animation.RELATIVE_TO_SELF, 0.5f);
    rotateAnimation.setDuration(2000);
    mImageView.startAnimation(rotateAnimation);
複製代碼

效果:圖片在2s內以圖片中心爲軸點,順時針旋轉360°,即完整轉一圈。

A4:透明度:

//法一:xml定義
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android" android:duration="2000" android:fromAlpha="1.0" android:toAlpha="0">
</alpha>

//在MainActivity中調用
    Animation alphaAnim = AnimationUtils.loadAnimation(this, R.anim.view_anim_alpha);
    mImageView.startAnimation(alphaAnim);
複製代碼
//法二:java代碼建立
AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0);
    alphaAnimation.setDuration(2000);
    mImageView.startAnimation(alphaAnimation);
複製代碼

效果:圖片在2s內從有到無。

A5:動畫集合:

//法一:xml定義
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="true" >
    
    <translate android:duration="2000" android:fromXDelta="0" android:fromYDelta="0" android:toXDelta="100%" android:toYDelta="100%"> />
    <scale android:duration="2000" android:fromXScale="1.0" android:fromYScale="1.0" android:pivotX="50%" android:pivotY="50%" android:toXScale="0.5" android:toYScale="0.5" /> 
    <rotate android:duration="2000" android:fromDegrees="0" android:toDegrees="360" android:pivotX="50%" android:pivotY="50%"/>
     <alpha android:duration="2000" android:fromAlpha="1.0" android:toAlpha="0"/>   
</set>

//在MainActivity中調用
    Animation setAnim = AnimationUtils.loadAnimation(this, R.anim.view_anim_set);
    mImageView.startAnimation(setAnim);
複製代碼

效果:以上四種動畫效果的疊加。圖片在2s內邊向右下角移動、邊縮小、邊旋轉、邊下降透明度至消失。


2 自定義動畫

實際項目中以上幾種動畫並不能知足咱們的需求,這時就須要自定義補間動畫

  • 步驟:

    1.繼承Animation

    2.重寫initialize()--->用於初始化

    3.重寫applyTransformation()--->用於進行矩陣變換

    常常須要藉助Camera來簡化矩陣變換

  • 實例:自定義補間動畫3D翻轉動畫


3 特殊使用場景

View動畫除了可做用在某個View對象上, 還能夠用在特殊的場景,例如:

  • 控制ViewGroup子View出場效果

  • Activity切換效果

    接下來將依次介紹:

A1:子View出場動畫

  • 經常使用場景:ListViewGridViewRecyclerView
  • 對應類:LayoutAnimation
  • XML文件建立在res/anim/
  • 根節點layoutAnimation,經常使用屬性:
layoutAnimation 
    |- delay="float"
    |- animationOrder="[normal|reverse | random]"
    |- animation="[@anim/res_id]"
複製代碼

delay:表示子元素開始動畫的延遲時間

好比,子元素入場動畫的時間週期是300ms,那麼該屬性值=0.5就表示每一個子元素都須要延遲150ms才能播放入場動畫。

animationOrder :表示子元素動畫的播放順序。可選模式:normal (正常順序)、random(隨機順序)、reverse(倒序)。

animation :爲子元素指定具體的入場動畫。

  • 建立方法:

法一:xml定義,分兩步

step1:定義layoutAnimation動畫

// res/anim/anim_layout.xml
<layoutAnimation 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:animation="@anim/anim_item"
    android:delay="0.5"
    android:animationOrder="normal">
</layoutAnimation>

// res/anim/anim_item.xml 效果:子項從右邊進入
<set 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="500"
    android:shareInterpolator="true"
    android:interpolator="@android:anim/accelerate_interpolator">
    <alpha android:fromAlpha="0" android:toAlpha="1" /> <translate android:fromXDelta="100%" android:toXDelta="0" /> </set> 複製代碼

step2:爲ViewGroup設置android:layoutAnimation屬性, 這裏假設爲Listview

//activity_main.xml
<ListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layoutAnimation="@anim/anim_layout"/>
複製代碼

法二:java代碼建立,經過LayoutAnimation類綁定

// res/anim/anim_item.xml 
<set xmlns:android="http://schemas.android.com/apk/res/android" android:duration="500" android:shareInterpolator="true" android:interpolator="@android:anim/accelerate_interpolator">
    <alpha android:fromAlpha="0" android:toAlpha="1" />
    <translate android:fromXDelta="100%" android:toXDelta="0" />
</set>
            
複製代碼
//main.java 
//和上述xml定義方法的效果相同
Animation animation = AnimationUtils.loadLayoutAnimation(this, R.anim.anim_item);
LayoutAnimationController controller = new LayoutAnimationController(animation);//對應android:animation屬性
controller.setDelay(0.5);//對應android:delay屬性 
controller.setOrder(LayoutAnimationController.ORDER_NORMAL); //對應android:animationOrder屬性
listView.setLayoutAnimation(controller);//對應android:layoutAnimation屬性
複製代碼

A2:Activity的切換效果

  • 該xml文件建立在res/anim/
  • Activity默認是有切換效果的,若須要自定義切換效果,須要用到overridePendingTransition(int inAnim, int outAnim)方法
  • 參數含義:(進入的Activity所需進行的動畫id,退出的Activity所需進行的動畫id)
  • 該方法調用在startActivity()finish()才生效。例如:
startActivity(intent);
overridePendingTransition(R.anim.enter_anim, R.anim.exit_anim);
複製代碼

2.1.2 幀動畫

  • 幀動畫也是View動畫的一種,它會按照順序播放一組預先定義好的圖片。對應類AnimationDrawable

  • 其中AnimationDrawable,筆者在進階之路 | 奇妙的Drawable之旅的文章末尾處也提到過。

Q1:幀動畫的建立

A1:經過xml定義:

  • 該xml文件建立在res/drawable/ 下。
  • 根節點animation-list,屬性android:oneshot表示是否執行一次;子節點item 下可設置輪播的圖片資源id和持續時間。例如:
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false">
    <item android:drawable="@drawable/xxx1" android:duration="500"/>
    <item android:drawable="@drawable/xxx2" android:duration="500"/>
    <item android:drawable="@drawable/xxx3" android:duration="500"/>
    <item android:drawable="@drawable/xxx4" android:duration="500"/>
</animation-list>
複製代碼

XML聲明好以後,將它做爲View的背景並經過AnimationDrawable來播放便可。代碼以下:

mView.setBackgroundResource(R.drawable.XXX);
AnimationDrawable animationDrawable = (AnimationDrawable)mView.getBackground();
animationDrawable.start();
複製代碼

A2:經過Java代碼動態建立

//和上述xml定義方法的效果相同
AnimationDrawable ad = new AnimationDrawable();//1.建立AnimationDrawable對象
    for (int i = 0; i < 4; i++) {//2.添加Drawable對象及其持續時間
        Drawable drawable = getResources().getDrawable(getResources().getIdentifier("xxx" + i, "drawable", getPackageName()));
        ad.addFrame(drawable, 500);
    }
    ad.setOneShot(false);//3.設置是否執行一次
    mView.setBackgroundResource(ad);//4.將幀動畫做爲view背景
    ad.start();//5.播放動畫
複製代碼
  • 注意:使用幀動畫要注意不能使用尺寸過大的圖片,不然容易形成OOM( 內存溢出)錯誤

  • 想要更進一步瞭解幀動畫的讀者,能夠看一下這篇文章:關於 逐幀動畫 的使用都在這裏了!

2.2 屬性動畫

2.2.1 插值器和估值器

用途:屬性動畫中的插值器和估值器能夠實現非勻速動畫

1 插值器(Interpolator)
  • 做用:根據時間流逝的百分比計算出當前屬性值改變的百分比。肯定了動畫效果變化的模式,如勻速變化、加速變化、減速變化等等。

  • 經常使用的系統內置插值器:

    a.線性插值器(LinearInterpolator):勻速動畫

    b.加速減速插值器(AccelerateDecelerateInterpolator):動畫兩頭慢中間快

    c.減速插值器(DecelerateInterpolator):動畫愈來愈慢

  • 可針對的對象:

    a.View動畫:插值器對應的屬性是android:interpolator

    b.屬性動畫:是實現非勻速動畫的重要手段。

  • 自定義插值器方法:實現 Interpolator / TimeInterpolator接口 ,而後複寫getInterpolation()

  • 補間動畫實現 Interpolator接口、屬性動畫實現TimeInterpolator接口。
  • TimeInterpolator接口是屬性動畫中新增的,用於兼容Interpolator接口。

插值器效果圖

2 類型估值器(TypeEvaluator)
  • 做用:根據當前屬性改變的百分比計算出改變後的屬性值
  • 經常使用的系統內置的估值器:
  • 整型估值器(IntEvaluator)
  • 浮點型估值器(FloatEvaluator)
  • Color屬性估值器(ArgbEvaluator)
  • 僅針對於屬性動畫,View動畫不須要類型估值器。是屬性動畫實現非勻速動畫的重要手段。
  • 自定義估值器方法:實現TypeEvaluator接口,而後複寫evaluate()

限於篇幅,本篇文章未介紹自定義插值器和估值器的實例,想要了解的讀者,能夠看下這篇文章:

Android 動畫:手把手帶你深刻了解神祕的插值器

2.2.2 屬性動畫與View動畫異同

View動畫 屬性動畫
實現方式 經過不斷圖形變換 經過動態改變對象屬性
做用對象 View 任何對象,甚至沒有對象
存放位置 anim animator
狀態變化 未真正改變View位置 真正改變View位置

2.2.3 實現方式

1 經過XML

res/animator/下可建立屬性動畫的XML文件。其中,根節點set對應AnimatorSet類,子節點objectAnimator對應ObjectAnimator類、animator對應ValueAnimator類。經常使用屬性:

//animator/XX.xml
<set android:ordering=["together" | "sequentially"]>

    <objectAnimator android:propertyName="string" android:duration="int" android:valueFrom="float | int | color" android:valueTo="float | int | color" android:startOffset="int" android:repeatCount="int" android:repeatMode=["repeat" | "reverse"] android:valueType=["intType" | "floatType"]/>

    <animator android:duration="int" android:valueFrom="float | int | color" android:valueTo="float | int | color" android:startOffset="int" android:repeatCount="int" android:repeatMode=["repeat" | "reverse"] android:valueType=["intType" | "floatType"]/>

    <set>
        ...
    </set>
</set>

//java
AnimatorSet set= AnimatorInflater.loadAnimator(myContext,R.anim.xxx);
set.setTarget(mBtn);
set.start();
複製代碼

首先介紹set標籤下的經常使用屬性:

  • ordering:設置動畫的時序關係。可選值:
  • together:默認值。表示動畫集合中的子動畫同時播放
  • equentially:表示動畫集合中的子動畫按照書寫的前後順序依次播放

接下來具體介紹屬性動畫的實現方式:

A.經過ObjectAnimator實現屬性動畫

  • 原理:經過直接對對象object)的屬性值進行改變操做,從而實現動畫效果。
  • 對應根節點objectAnimator
  • 經常使用屬性介紹:
  • propertyName:屬性動畫做用的屬性名稱

  • duration: 動畫持續時長

  • startOffset:設置動畫執行以前的等待時長

  • repeatCount:動畫重複執行的次數;默認爲0,表示只播放一次。設置爲**-1或infinite**,表示無限重複。

  • repeatMode:動畫重複執行的模式。可選值:

    a.restart:表示連續重複,爲默認值。

    b.reverse :表示逆向重複

  • valueFrom:動畫初始值

  • valueTo:動畫結束值

  • valueType:表示propertyName指定的屬性值類型。可選值:

    a.intType :以上兩個value屬性值爲整型。

    b.floatType:即以上兩個value屬性值爲浮點型,爲默認值。

    c.color:若propertyNamecolor,則無需設置該屬性。

B.經過ValueAnimator實現屬性動畫

  • 原理:經過不斷控制(value)的變化,再不斷手動賦給對象的屬性,從而實現動畫效果。

ObjectAnimatorValueAnimator類的區別:

  • ValueAnimator 類是先改變值,而後手動賦值給對象的屬性從而實現動畫;是間接對對象屬性進行操做
  • ObjectAnimator 類是先改變值,而後自動賦值給對象的屬性從而實現動畫;是直接對對象屬性進行操做
  • 對應根節點animator
  • 經常使用屬性比objectAnimator標籤少一個android:propertyName屬性,其餘相同
2 經過JAVA

實際開發中建議用JAVA的方式來實現屬性動畫,緣由:

  • 經過代碼來實現比較簡單
  • 不少時候屬性的起始值沒法提早肯定

A.ObjectAnimator

注意:這裏ObjectAnimator 做用的屬性必須有set方法

get方法可選;當動畫沒有設置初始值的時候,get必須存在)

  • 方法:
//第一個參數是對象,第二個是對象的屬性名字,第3個是值的變化,能夠是ofFloat或者是ofInt,根據參數的類型直接寫
ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(tv,"alpha",1,0,1); 
//設置持續時間
objectAnimator.setDuration(2000);
 objectAnimator.start();
複製代碼
  • 源碼分析:
//ofFloat直接返還一個 ObjectAnimator對象
public static ObjectAnimator ofFloat (Object target,String propertyName,float... values){
			ObjectAnimator anim=new ObjectAnimator (target,propertyName);
			anim.setFloatValues(values);
		return anim;
}
複製代碼

B.ValueAnimator

  • ValueAnimator不提供任何動畫效果,更像一個數值發生器,用來產生有必定規律的數字,從而讓調用者控制動畫的實現過程。
  • 通常在AnimatorUpdateListener/AnimatorListenerAdapter(在下文會詳細介紹)中監聽數值的變化,而完成動畫的變換

測試實例:

//實現顏色的漸變
    ValueAnimator valueAnimator = ValueAnimator.ofArgb(0xFFFF5454, 0xFF5DDE5D, 0xFF5DBEDE);
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            int color = (int) animation.getAnimatedValue();
            button.setBackgroundColor(color);
        }
    });
    valueAnimator.setDuration(2000);
    //記得start
    valueAnimator.start();
複製代碼

C.組合動畫

C1.AnimatorSet

能夠實現有前後順序的組合動畫

  • 重點方法:
  • play:傳入一個 Animator 對象 ,會返回一個AnimatorSet.Builder的實例

  • Builder中有4個方法:

    a.after(Animator):將現有動畫插入到傳入的動畫以後執行

    b.before(Animator):將現有動畫插入到傳入的動畫以前執行

    c.with(Animator):將現有動畫和傳入的動畫同時執行。

    d.after(Long):將現有動畫延遲指定毫秒後執行。

執行順序

  • 實例使用:
ObjectAnimator alphaAnimator =ObjectAnimator.ofFloat(tv, "alpha", 1, 0, 1);
ObjectAnimator rotateAnimator =ObjectAnimator.ofFloat(tv, "rotation", 0, 360, 0);
rotateAnimator.setDuration(15000);
ObjectAnimator scaleAnimator =ObjectAnimator.ofFloat(tv, "scaleX", 1, 2, 1);
ObjectAnimator translateAnimator =ObjectAnimator.ofFloat(tv, "translationX", 0, 100, 0);

AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(alphaAnimator)
.with(rotateAnimator)
.after(scaleAnimator)
.before(translateAnimator);
animatorSet.setDuration(2000).start();
複製代碼

實例執行順序

C2:PropertyValuesHolder

能夠實現同時執行的組合動畫

  • 實例使用:
//新建動畫類 
PropertyValuesHolder valuesHolder1=PropertyValuesHolder.ofFloat("scaleX",1.0f,1.5f);
PropertyValuesHolder valuesHolder2=PropertyValuesHolder.ofFloat("rotationX",0f,90.0f);
//新建ObjectAnimator
ObjectAnimator animator=ObjectAnimator.ofPropertyValuesHolder(view,valuesHolder1,valuesHolder2);
//開啓動畫 
animator.setDuration(200).start();
複製代碼

2.2.4 監聽器

屬性動畫主要使用兩個接口:AnimatorUpdateListener&AnimatorListener來監聽動畫的播放過程。

  • AnimatorListener:監聽動畫的開始、結束、取消以及重複播放。以下:
public static interface AnimatorListener {
    void onAnimationStart(Animator animation); //動畫開始
    void onAnimationEnd(Animator animation); //動畫結束
    void onAnimationCancel(Animator animation); //動畫取消
    void onAnimationRepeat(Animator animation); //動畫重複播放
}
複製代碼

爲方便開發,系統提供了AnimatorListenerAdapter類,它是AnimatorListener的適配器,如此可有選擇複寫上述四個方法。

  • AnimatorUpdateListener:監聽整個動畫過程。每播放一幀,onAnimationUpdate()就會被調用一次,以下:
public interface AnimatorUpdateListener {
  void onAnimationUpdate(ValueAnimator var1);//在屬性動畫的屬性值變化是回調。
}
複製代碼

2.2.5 對任意屬性作動畫

  • 需知足的條件:
  • 對象必須提供set方法,若未傳遞初始值給動畫,還需提供get方法(由於系統須要去取初始值)
  • set方法對屬性所作的改變必須能經過某種方式反映出來(例如:UI效果改變)
  • 解決方法:

    A.給對象加上getset方法

這個方法通常不可行,由於大多數的時候,咱們沒有權限

​ B.用包裝類的方式,間接提供getset方法

實例:

class MyView{
private View mTarget;
private MyView (View view){
mTarget =view;
}
    
//屬性的get方法
public int getWidth(){
return mTarget.getLayoutParams().width;
}

//屬性的set方法
public void setWidth(int width){
mTarget.getLayoutParams().width=width;
mTarget.requestLayout();
}
}
複製代碼
MyView myView = new MyView(mButton);
ObjectAnimator.ofInt(myView, "width", 500).setDuration(500).start();
複製代碼

C.用ValueAnimator監聽動畫過程,本身改變屬性

測試實例:

/** * 改變對象的寬度 * @param target 對象 * @param start 起始值 * @param end 目標值 */
    private void performAnimate(final View target, final int start, final int end) {
        ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //持有一個IntEvaluator對象,方便下面估值的時候使用
                IntEvaluator evaluator = new IntEvaluator();
                //獲得當前動畫的進度值
                float fraction = animation.getAnimatedFraction();
                //調用整型估值器,經過比例計算出寬度,而後設給Btn
                target.getLayoutParams().width = evaluator.evaluate(fraction, start, end);
                target.requestLayout();
            }
        });
        valueAnimator.setDuration(5000).start();
    }
複製代碼

2.2.6 工做原理

  • 整體思路:在必定時間間隔內,經過不斷對值進行改變,並不斷將該值賦給對象的屬性,從而實現該對象在該屬性上的動畫效果。

具體體如今 :

  • 建立屬性動畫時,若未設初值,則系統會經過該屬性的get()方法獲取初始值。故屬性動畫要求必須提供屬性的get()方法
  • 在動畫播放的過程當中,利用時間插值器和類型估值器獲取改變後的屬性值
  • 將改變後的屬性值經過set()方法設置到對象中。故屬性動畫要求必須提供屬性的set()方法
  • 具體流程:

get/set方法是經過反射調用的,筆者將帶你深刻屬性動畫的源碼,探究其緣由:

屬性動畫源碼解析

三.注意事項

恭喜你!已經看完了前面的文章,相信你對Animation已經有必定深度的瞭解!

在使用過程當中,也有一些事項是須要咱們注意的:

  • OOM問題

這個問題主要出如今幀動畫中,當圖片數量較多且圖片較大時易出現OOM,因此平常開發中儘可能避免使用幀動畫

  • 內存泄漏
  • 屬性動畫中有一類無限循環的動畫(repeatCount=-1),這類動畫須要在Activity退出時及時中止,不然致使Activity沒法釋放形成內存泄漏
  • View動畫不存在這個問題
  • View動畫的問題

View動畫是對View的影像作動畫,不是真正改變View的狀態,有時候出現動畫完成後View沒法隱藏的現象(setVisibility(View.GONE)失效),須要調用view.clearAnimation()清除View動畫

  • 不要使用px

在進行動畫的過程當中,儘可能使用dp,使用px會致使在不一樣的設備上有不一樣的效果

想要了解具體緣由的讀者,筆者給您推薦一篇文章:dp、sp、px區別

  • 動畫元素的交互

Android3.0以後,屬性動畫的單擊事件觸發位置爲移動後的位置,可是View動畫仍在原位置

  • 硬件加速

Android4.0開始默認開啓硬件加速


若是文章對您有一點幫助的話,但願您能點一下贊,您的點贊,是我前進的動力

本文參考連接:

相關文章
相關標籤/搜索