天天看點

Android 開發文檔 - 動畫AnimationAnimatorSetView 動畫屬性動畫

文章目錄

  • Animation
  • AnimatorSet
  • View 動畫
    • 補間動畫
      • Animation
        • 常用方法
      • Transformation
      • Camera
        • 常用方法
      • Matrix
        • 常用方法
          • 如何使用前乘後乘?
    • 幀動畫
      • 靜态可繪制資源
      • 矢量可繪制對象
  • 屬性動畫
    • 插值器 & 估值器
    • 屬性動畫優于 View 動畫的地方
    • 自動為布局更新添加動畫
    • 使用 ViewPropertyAnimator 添加動畫效果
    • StateListDrawable
    • StateListAnimator
      • 用法
        • 執行個體
    • ColorStateList
    • Activity 過渡
      • 共享元素過渡

https://developer.android.com/training/animation/overview

https://developer.android.com/guide/topics/resources/animation-resource

Animation

ValueAnimator - <animator>

ObjectAnimator - <objectAnimator>

AnimatorSet - <set>

AnimatorSet

Animation 容器,可以包含多個 Animation 類。

使用方法:

AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
    R.animator.property_animator);
set.setTarget(myObject);
set.start();
           

setTarget() 即可設定一個用于 AnimatorSet 的所有子項的目标對象。

View 動畫

使用 View 動畫架構可以建立兩種類型的動畫:

  • 補間動畫:通過使用 Animation 包 (android.view.animation) 對單個 View 執行一系列轉換(位置,大小,旋轉度等)來建立動畫
  • 幀動畫:通過使用 AnimationDrawable 類按順序顯示一系列圖檔來建立動畫。

注意:無論動畫如何移動或調整大小,容納動畫的視圖的邊界不變,但是動畫仍會被繪制到相應視圖的邊界之外,且不被剪裁。隻有當動畫超出了父級視圖的邊界,系統才對其進行剪裁。

補間動畫

檔案位置:res/anim/xxx.xml

檔案必須具有一個根元素,可以是 <alpha>、<scale>、<translate>、<rotate> 或包含一組(或多組)其他動畫元素(甚至是嵌套的 <set> 元素)的 <set> 元素。

使用方法:

作為 startAnimation() 的替代方法,您可以使用 Animation.setStartTime() 定義動畫的開始時間,然後使用 View.setAnimation() 将動畫配置設定到視圖。

Animation

https://developer.android.com/reference/android/view/animation/Animation
java.lang.Object
   ↳	android.view.animation.Animation
           

可以應用于 Views,Surfaces 或其他對象的動畫的抽象。

已知直接子類:AlphaAnimation, AnimationSet, RotateAnimation, ScaleAnimation, TranslateAnimation

常用方法

initialize(int width, int height, int parentWidth, int parentHeight):使用要制作動畫的對象以及對象父對象的尺寸初始化此動畫。當已知要動畫的對象及其父對象的大小時,并且在調用 getTransformation(long, Transformation) 之前,解釋動畫的對象應調用此方法。

applyTransformation(float interpolatedTime, Transformation t):getTransformation 的助手。子類應實作此功能,以在給定插值的情況下應用其變換。

getTransformation(long currentTime, Transformation outTransformation, float scale):擷取要在指定時間點應用的轉換。如果動畫仍在運作,則傳回 true

setFillAfter (boolean fillAfter):如果 fillAfter 為 true,則此動畫執行的轉換将在完成時保留。預設為 false,即在動畫完成時還原原貌。請注意,這适用于單個動畫和使用 AnimationSet 連結的多個轉換動畫。

Transformation

https://developer.android.com/reference/android/view/animation/Transformation
java.lang.Object
   ↳	android.view.animation.Transformation
           

定義要在動畫的某個時間點應用的變換。

Camera

https://developer.android.com/reference/android/graphics/Camera
java.lang.Object
   ↳	android.graphics.Camera
           

攝影機執行個體可用于計算3D轉換并生成可應用于例如Canvas的矩陣。

常用方法

getMatrix(Matrix matrix):計算與目前變換對應的矩陣,并将其複制到提供的矩陣對象。

restore():恢複儲存的狀态(如果有)。

save():儲存錄影機狀态。

getLocationZ():擷取相機的z位置。

setLocation(float x, float y, float z):設定錄影機的位置。

translate (float x, float y, float z):在所有三個軸上應用平移變換。

Matrix

https://developer.android.com/reference/android/graphics/Matrix
java.lang.Object
   ↳	android.graphics.Matrix
           

Matrix 類包含一個用于轉換坐标的 3x3 矩陣。

常用方法

preTranslate(float dx, float dy):前乘,相當于矩陣右乘;T:平移量,齊次坐标。 M’ = M * T(dx, dy)

postTranslate(float dx, float dy)::後乘,相當于矩陣左乘;T:平移量,齊次坐标。M’ = T(dx, dy) * M

如何使用前乘後乘?

正确使用方式就是先構造正常的 Matrix 乘法順序,之後根據情況使用 pre 和 post 來把這個順序實作。

還是用一個最簡單的例子了解,假設需要圍繞某一點旋轉。

可以用這個方法 xxxRotate(angle, pivotX, pivotY) ,由于我們這裡需要組合構造一個 Matrix,是以不直接使用這個方法。

首先,有兩條基本定理:

  • 所有的操作(旋轉、平移、縮放、錯切)預設都是以坐标原點為基準點的。
  • 之前操作的坐标系狀态會保留,并且影響到後續狀态。

基于這兩條基本定理,我們可以推算出要基于某一個點進行旋轉需要如下步驟:

  1. 先将坐标系原點移動到指定位置,使用平移 T
  2. 對坐标系進行旋轉,使用旋轉 S (圍繞原點旋轉)
  3. 再将坐标系平移回原來位置,使用平移 -T

具體公式如下:

M ′ = M ∗ T ∗ R ∗ − T = T ∗ R ∗ − T M' = M*T*R*-T = T*R*-T M′=M∗T∗R∗−T=T∗R∗−T

M 為原始矩陣,是一個機關矩陣, M‘ 為結果矩陣, T 為平移, R為旋轉。

按照公式寫出來的僞代碼如下:

Matrix matrix = new Matrix();
matrix.preTranslate(pivotX,pivotY);
matrix.preRotate(angle);
matrix.preTranslate(-pivotX, -pivotY);
           

圍繞某一點操作可以拓展為通用情況,即:

Matrix matrix = new Matrix();
matrix.preTranslate(pivotX,pivotY);
// 各種操作,旋轉,縮放,錯切等,可以執行多次。
matrix.preTranslate(-pivotX, -pivotY);
           

公式為:

M ′ = M ∗ T ∗ . . . ∗ − T = T ∗ . . . ∗ − T M' = M*T* ... *-T = T* ... *-T M′=M∗T∗...∗−T=T∗...∗−T

但是這種方式,兩個調整中心的平移函數就拉的太開了,是以通常采用這種寫法:

Matrix matrix = new Matrix();
// 各種操作,旋轉,縮放,錯切等,可以執行多次。
matrix.postTranslate(pivotX,pivotY);
matrix.preTranslate(-pivotX, -pivotY);
           

這樣公式為:

M ′ = T ∗ M ∗ . . . ∗ − T = T ∗ . . . ∗ − T M' = T*M* ... *-T = T* ... *-T M′=T∗M∗...∗−T=T∗...∗−T

可以看到最終化簡結果是相同的。

是以說,pre 和 post 就是用來調整乘法順序的,正常情況下應當正向進行建構出乘法順序公式,之後根據實際情況調整書寫即可。

在構造 Matrix 時,個人建議盡量使用一種乘法,前乘或者後乘,這樣操作順序容易确定,出現問題也比較容易排查。當然,由于矩陣乘法不滿足交換律,前乘和後乘的結果是不同的,使用時應結合具體情景分析使用。

安卓自定義View進階-Matrix原理

示例:Android - 自定義 3D 繞 Y 軸旋轉動畫

幀動畫

https://developer.android.com/guide/topics/graphics/drawable-animation

檔案位置:res/drawable/ 目錄下

靜态可繪制資源

  1. 可以使用 AnimationDrawable 類 API 在代碼中定義動畫幀
  2. 使用單個 XML 檔案(其中列出構成動畫的各個幀)可更輕松地完成此操作。

res/drawable/ 目錄中定義 rocket_thrust.xml 檔案:

<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="true">
    <item android:drawable="@drawable/rocket_thrust1" android:duration="200" />
    <item android:drawable="@drawable/rocket_thrust2" android:duration="200" />
    <item android:drawable="@drawable/rocket_thrust3" android:duration="200" />
</animation-list>
           

oneshot 為 true 表示動畫僅播放一次,并停留在最後幀;為 false 表示一直循環

使用:

ImageView rocketImage = (ImageView) findViewById(R.id.rocket_image);
rocketImage.setBackgroundResource(R.drawable.rocket_thrust);
AnimationDrawable rocketAnimation = (AnimationDrawable) rocketImage.getBackground();

rocketImage.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
      rocketAnimation.start();
    }
});
           

對 AnimationDrawable 調用的 start() 方法不能在 Activity 的 onCreate() 方法期間調用,因為 AnimationDrawable 尚未完全附加到視窗。可以 onStart() 方法中無需互動而進行調用。

矢量可繪制對象

矢量可繪制對象是一種無需像素化或進行模糊處理即可縮放的可繪制對象。借助 AnimatedVectorDrawable 類(以及用于實作向後相容的 AnimatedVectorDrawableCompat),您可以為矢量可繪制對象的屬性添加動畫效果。

  1. 定義矢量可繪制對象 res/drawable/vectordrawable.xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:height="64dp"
    android:width="64dp"
    android:viewportHeight="600"
    android:viewportWidth="600">
    <group
        android:name="rotationGroup"
        android:pivotX="300.0"
        android:pivotY="300.0"
        android:rotation="45.0" >
        <path
            android:name="v"
            android:fillColor="#000000"
            android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
    </group>
</vector>
           

<group> 元素定義一組路徑或子組,而 <path> 元素定義要繪制的路徑。

  1. 為 <group> 和 <path> 元素的屬性添加動畫效果 res/drawable/animatorvectordrawable.xml:
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
  android:drawable="@drawable/vectordrawable" >
    <target
        android:name="rotationGroup"
        android:animation="@animator/rotation" />
    <target
        android:name="v"
        android:animation="@animator/path_morph" />
</animated-vector>
           

添加動畫效果之後的矢量可繪制對象定義會按矢量可繪制對象中各個組和路徑的名稱對其進行引用。

  1. ObjectAnimator 或 AnimatorSet 對象定義動畫

res/animator/rotation.xml 會将目标組旋轉 360 度:

<objectAnimator
    android:duration="6000"
    android:propertyName="rotation"
    android:valueFrom="0"
    android:valueTo="360" />
           

res/animator/path_morph.xml 會将矢量可繪制對象的路徑從一個形狀變為另一個形狀。這兩個路徑都必須相容變形:具有相同數量的指令,每個指令具有相同數量的參數。

<set xmlns:android="http://schemas.android.com/apk/res/android">
    <objectAnimator
        android:duration="3000"
        android:propertyName="pathData"
        android:valueFrom="M300,70 l 0,-70 70,70 0,0   -70,70z"
        android:valueTo="M300,70 l 0,-70 70,0  0,140 -70,0 z"
        android:valueType="pathType" />
</set>
           

生成的 AnimatedVectorDrawable:

Android 開發文檔 - 動畫AnimationAnimatorSetView 動畫屬性動畫

屬性動畫

https://developer.android.com/guide/topics/graphics/prop-animation

檔案位置:res/animator/ 下

視圖動畫系統通過更改繪制視圖對象的方式來轉換視圖對象。這會産生不好的效果,例如,某個對象已經在螢幕的其他位置繪制,但它仍位于其原始位置。

屬性動畫系統可以通過更改視圖對象中的實際屬性來為螢幕上的視圖添加動畫效果。此外,當視圖的屬性發生更改時,視圖還會自動調用 invalidate() 方法來重新整理螢幕。

ValueAnimator:在指定的時間段内執行動畫。

ValueAnimator animation = ValueAnimator.ofFloat(0f, 100f);
animation.setDuration(1000);
animation.start();
           

上述代碼中,當 start() 方法運作時,ValueAnimator 會開始計算 1000ms 時長内 0 和 100 之間的動畫的值。

添加 AnimatorUpdateListener 來擷取動畫的值,為特定屬性使用:

animation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator updatedAnimation) {
        // 您可以為與動畫值類型相同的屬性使用動畫值。
        // 此例中,您可以為 translationX 屬性使用 floatX 值。
        float animatedValue = (float)updatedAnimation.getAnimatedValue();
        textView.setTranslationX(animatedValue);
    }
});
           

ObjectAnimator:在指定的一段時間内為對象的特定屬性建立動畫。

就上例,使用 ObjectAnimator 比 ValueAnimator 簡單:

ObjectAnimator animation = ObjectAnimator.ofFloat(textView, "translationX", 100f);
animation.setDuration(1000);
animation.start();
           

插值器 & 估值器

ValueAnimator 包含 TimeInterpolator 和 TypeEvaluator;前者用于定義動畫插值,後者用于定義如何計算正在添加動畫效果的屬性的值。

ValueAnimator 将基于動畫時長和已播放時長計算動畫已完成百分比(在 0 和 1 之間),計算完動畫已完成百分比後,它會調用目前設定的 TimeInterpolator 來計算插值分數。插值分數會将動畫已完成百分比映射為一個新分數(如果是線性插值器,則插值分數 = 動畫已完成百分比;如果是加速減速插值器,剛開始加速階段,則插值分數 < 動畫已完成百分比,見下面插值器傳回的實作)。計算插值分數後,ValueAnimator 會調用相應的 TypeEvaluator,以根據動畫的插值分數、起始值和結束值來計算要添加動畫效果的屬性的值(起始值 + 插值分數 * (結束值 - 起始值))。

LinearInterpolator:

@Override
public float getInterpolation(float input) {
    return input;
}
           

AccelerateDecelerateInterpolator:

@Override
public float getInterpolation(float input) {
    return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}
           

input 是 0 ~ 1 之間的數, c o s ( i n p u t ∗ π + π ) / 2 cos(input*\pi+\pi)/2 cos(input∗π+π)/2 是值域為 -0.5 到 0.5 的增函數,最終傳回的插值分數從 0 到 1 先快速後緩速遞增,起到加速減速效果。

Float 類型 TypeEvaluator 的實作:fraction 就是 getInterpolation 傳回的值

public class FloatEvaluator implements TypeEvaluator {

    public Object evaluate(float fraction, Object startValue, Object endValue) {
        float startFloat = ((Number) startValue).floatValue();
        return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);
    }
}
           
可用插值器:https://developer.android.com/guide/topics/resources/animation-resource#Interpolators
可用估值器:Android 系統可以識别的類型為 int、float 或顔色,分别由 IntEvaluator、FloatEvaluator 和 ArgbEvaluator 類型評估程式提供支援。

屬性動畫優于 View 動畫的地方

View 動畫系統:

  • 僅提供為 View 對象添加動畫效果的功能,是以,如果您想為非 View

    對象添加動畫效果,則必須實作自己的代碼才能做到。

  • 僅公開 View 對象的部分方面來供您添加動畫效果;例如,您可以對視圖的縮放和旋轉添加動畫效果,但無法對背景顔色這樣做。
  • 隻會在繪制視圖的位置進行修改,而不會修改實際的視圖本身。例如,如果您為某個按鈕添加了動畫效果,使其可以在螢幕上移動,該按鈕會正确繪制,但能夠點選按鈕的實際位置并不會更改。

自動為布局更新添加動畫

為布局添加如下屬性:

<LinearLayout android:id="@+id/container"
    android:animateLayoutChanges="true"
    ...
/>
           

現在,您隻需為布局添加、移除或更新項目,系統就會自動對這些項目進行動畫處理:

Android 開發文檔 - 動畫AnimationAnimatorSetView 動畫屬性動畫

使用 ViewPropertyAnimator 添加動畫效果

ViewPropertyAnimator 有助于使用單個底層 Animator 對象輕松為 View 的多個屬性并行添加動畫效果。它的行為方式與 ObjectAnimator 非常相似,因為它會修改視圖屬性的實際值,但在同時為多個屬性添加動畫效果時,它更為高效。

以下代碼段展示了在同時為視圖的 x 和 y 屬性添加動畫效果時,使用多個 ObjectAnimator 對象、使用單個 ObjectAnimator 對象以及使用 ViewPropertyAnimator 的差別。

多個 ObjectAnimator 對象:

ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();
           

一個 ObjectAnimator:

PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvhY).start();
           

ViewPropertyAnimator:

StateListDrawable

https://developer.android.com/reference/android/graphics/drawable/StateListDrawable
java.lang.Object
   ↳	android.graphics.drawable.Drawable
 	   ↳	android.graphics.drawable.DrawableContainer
 	 	   ↳	android.graphics.drawable.StateListDrawable
           

使您可以将多個圖形圖像配置設定給單個Drawable,并通過字元串ID值替換可見項。

可以使用

<selector>

元素在XML檔案中定義它。每個狀态Drawable都在嵌套

<item>

元素中定義。有關更多資訊,請參見Drawable Resources指南。

StateListAnimator

https://developer.android.com/reference/android/animation/StateListAnimator
java.lang.Object
   ↳	android.animation.StateListAnimator
           

隻要指定的視圖狀态(例如“按下”或“聚焦”)發生更改,就會調用該動畫。

有如下狀态:

android:state_activated:State value for StateListDrawable, set when a view or its parent has been “activated” meaning the user has currently marked it as being of interest.

android:state_active:State value for StateListDrawable, set when a view or drawable is considered “active” by its host.

android:state_checkable:State identifier indicating that the object may display a check mark.

android:state_checked:State identifier indicating that the object is currently checked.

android:state_enabled:State value for StateListDrawable, set when a view is enabled.

android:state_first:State value for StateListDrawable, set when a view or drawable is in the first position in an ordered set.

android:state_focused:State value for StateListDrawable, set when a view has input focus.

android:state_last:State value for StateListDrawable, set when a view or drawable is in the last position in an ordered set.

android:state_middle:State value for StateListDrawable, set when a view or drawable is in the middle position in an ordered set.

android:state_pressed:State value for StateListDrawable, set when the user is pressing down in a view.

android:state_selected:State value for StateListDrawable, set when a view (or one of its parents) is currently selected.

android:state_single:State value for StateListDrawable, set when a view or drawable is considered “single” by its host.

android:state_window_focused:State value for StateListDrawable, set when a view’s window has input focus.

https://developer.android.com/reference/android/R.attr#state_checked

用法

使用根

<selector>

元素和子

<item>

元素在 XML 資源中定義 StateListAnimator,每個元素都指定一個由 StateListAnimator 類定義的不同視圖狀态。每個

<item>

可以包含一個屬性動畫集的定義,或者不需要任何動畫定義,僅使用 drawable 屬性定義不同狀态的圖檔。

res/xml/animate_scale.xml 展示視圖的縮放,按下後更改視圖的 x 和 y 比例:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- the pressed state; increase x and y size to 150% -->
    <item android:state_pressed="true">
        <set>
            <objectAnimator android:propertyName="scaleX"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1.5"
                android:valueType="floatType"/>
            <objectAnimator android:propertyName="scaleY"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1.5"
                android:valueType="floatType"/>
        </set>
    </item>
    <!-- the default, non-pressed state; set x and y size to 100% -->
    <item android:state_pressed="false">
        <set>
            <objectAnimator android:propertyName="scaleX"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1"
                android:valueType="floatType"/>
            <objectAnimator android:propertyName="scaleY"
                android:duration="@android:integer/config_shortAnimTime"
                android:valueTo="1"
                android:valueType="floatType"/>
        </set>
    </item>
</selector>
           

使用:

<Button android:stateListAnimator="@xml/animate_scale"
        ... />
           

代碼中添加:使用 AnimatorInflater.loadStateListAnimator() 方法,然後使用 View.setStateListAnimator() 方法将 Animator 配置設定給相應視圖。

執行個體

res/drawable/button_bg_seletor.xml 展示視圖圖檔的切換,state_pressed 預設狀态為 false:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:state_focused="true" android:drawable="@drawable/button_p" />
    <item android:state_pressed="true" android:drawable="@drawable/button_p" />
    <item android:drawable="@drawable/button_n" />
</selector>
           

可以直接作為 drawable 使用:

<ImageView android:src="@drawable/button_bg_seletor"
        ... />
<TextView android:drawableTop="@drawable/button_bg_seletor"
		... />
           

ColorStateList

https://developer.android.com/reference/android/content/res/ColorStateList.html
java.lang.Object
   ↳	android.content.res.ColorStateList
           

Lets you map View state sets to colors.

ColorStateLists are created from XML resource files defined in the “color” subdirectory directory of an application’s resource directory. The XML file contains a single “selector” element with a number of “item” elements inside. For example:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:state_focused="true"
          android:color="@color/sample_focused" />
  <item android:state_pressed="true"
          android:state_enabled="false"
          android:color="@color/sample_disabled_pressed" />
  <item android:state_enabled="false"
          android:color="@color/sample_disabled_not_pressed" />
  <item android:color="@color/sample_default" />
</selector>
           

This defines a set of state spec / color pairs where each state spec specifies a set of states that a view must either be in or not be in and the color specifies the color associated with that spec.

Activity 過渡

在 Theme 中将 android:windowAnimationStyle 指向你設定的過渡動畫類型:

在 style 中設定過渡動畫類型的具體類型 & 其屬性動畫:

<style name="AnimaActivity">
	<item name="android:activityOpenEnterAnimation">@anim/activity_slide_enter_right</item>
    <item name="android:activityOpenExitAnimation">@anim/activity_slide_exit_left</item>
    <item name="android:activityCloseEnterAnimation">@anim/activity_slide_enter_left</item>
    <item name="android:activityCloseExitAnimation">@anim/activity_slide_exit_right</item>
</style>
           

在 res/anim 中建立各過渡動畫類型的具體變換,如 activity_slide_enter_right.xml:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
    <translate
        android:duration="300"
        android:fromXDelta="100%"
        android:toXDelta="0" />

    <alpha
        android:duration="300"
        android:fromAlpha="0.0"
        android:toAlpha="1.0" />

</set>
           

共享元素過渡

https://developer.android.google.cn/training/transitions/start-activity