前兩篇《天啦嚕!原來Android補間影片可以這么玩》和《天啦嚕!原來Android幀影片這么簡單》重點講述了Android開發程序中補間影片和幀影片知識點,本篇文章我們重點總結一下屬性影片的使用和原理,
Android影片系列:
- 《天啦嚕!原來Android補間影片可以這么玩》
- 《天啦嚕!原來Android幀影片這么簡單》
- 《天啦嚕!原來Android屬性影片也不過如此》
什么是屬性影片
在一段時間內通過修改物件的屬性而形成的影片叫屬性影片(Property Animation),Google官方在Android 3.0添加Property Animation,屬性影片的主要是修改物件的屬性,如 View 的背景顏色、透明值、位置等,
屬性影片和補間影片的區別
有同學可能會問不是已經有補間影片嗎,為什么要引入屬性影片?換句話說,Property Animation 到底能干哪些 Tween Animation 不能干的活呢?
Tween Animation 存在的問題:
- Tween Animation 只能作用于 View,不能作用于普通 Object 的屬性,
- Tween Animation 只能改變 View 的一部分屬性,Tween Animation 只支持修改 View 的這幾個方面:Alpha、Scale、Translate、Rotate 和這些的組合,一旦想要改變的 View 的屬性不在這個范圍內,Tween Animation 就無能為力了,如 View 的 BackgroundColor,
- Tween Animation 只能改變 View 的“表面”位置,不能改變 View 的實際位置,
屬性影片相關類
屬性影片涉及的類主要有:
- Animator,所有 Animator 的父類,主要用于定義通用的介面,
- AnimatorSet,主要用于組合多個屬性影片,
- ValueAnimator,屬性影片的一種,主要用于根據起始值和終止值產生影片,只負責產生在起始值和終止值之間的值,
不負責更新界面,需要用戶自己實作更新界面的邏輯, - ObjectAnimator,屬性影片的一種,主要用于根據起始值和終止值產生影片,并將影片產生的值設定在目標物件上,
- TimeAnimator,提供了一個簡單的回呼機制,通過 TimeAnimator.TimeListener,在影片的每一幀處通知你,這個影片器沒有時間,插值或是物件值設定,回呼監聽器為每一幀影片接受資訊,包括總運行時間和從前一幀到現在的運行時間,
繼承結構如下:

ValueAnimator和ObjectAnimator主要區別
該類作為ValueAnimator的子類不僅繼承了ValueAnimator的所有方法和特性,并且還封裝很多實用的方法,方便開發人員快速實作影片,同時,由于屬性值會自動更新,使用ObjectAnimator實作影片不需要像ValueAnimator那樣必須實作 ValueAnimator.AnimatorUpdateListener ,因此實作任意物件的影片顯示就更加容易了,我們在大部分的開發作業中,都會使用ObjectAnimator而非ValueAnimator實作我們所需的影片效果,
屬性影片實作形式
屬性影片的實作形式有兩種:xml創建和code實作,其中xml創建的xml影片檔案要放在res/animator目錄下,注意此處和補間影片(Tween Animation)存放位置不同,
通常情況下屬性影片一般建議通過代碼進行實作,因為他更靈活,尤其是在自定義View中常常有屬性影片的身影,當然也需要根據實際場景自行選擇,下邊就通過這兩種形式來總結一下屬性影片幾個類的使用,
ValueAnimator
ValueAnimator是Property Animation系統的核心類,它包含了配置Property Animation屬性的大部分方法,那要實作一個Property Animation,都需要直接或間接使用ValueAnimator類,
一般使用ValueAnimator實作影片分為以下幾個步驟:
- 呼叫ValueAnimation類中的ofInt(int…values)、ofFloat(String propertyName,float…values)等靜態方法實體化ValueAnimator物件;
- 呼叫addUpdateListener(AnimatorUpdateListener mListener)方法為ValueAnimator物件設定屬性變化的監聽器,并在AnimatorUpdateListener 中的實作方法為目標物件的屬性設定計算好的屬性值,
- 創建自定義的插值器(Interpolator),呼叫setInterpolator(TimeInterpolator value)為ValueAniamtor設定自定義的Interpolator;(可選,不設定默認為預設值)
- 創建自定義的估值器(TypeEvaluator),呼叫setEvaluator(TypeEvaluator value)為ValueAnimator設定自定義的TypeEvaluator;(可選,不設定默認為預設值)
- 設定影片的持續時間、是否重復及重復次數等屬性;
- 為ValueAnimator設定目標物件并開始執行影片,
需要注意目標物件的需要被設定的屬性必須擁有get\set方法,格式類似 set(),
通過XML創建
語法:
<animator
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="int"
android:interpolator="@[package:]anim/interpolator_resource"
android:valueType=["intType" | "floatType"]
android:valueFrom="float | int | color"
android:valueTo="float | int | color"
android:startOffset="int"
android:repeatCount="int"
android:repeatMode=["repeat" | "reverse"]
/>

示例:
//1. 創建 value_animator.xml
<?xml version="1.0" encoding="utf-8"?>
<animator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1800"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:valueType="floatType"
android:valueFrom="-100"
android:valueTo="800"
android:startOffset="0"
android:repeatCount="infinite"
android:repeatMode="reverse"
/>
//2. 在代碼中使用 value_animator
ValueAnimator mValueAnimator = (ValueAnimator) AnimatorInflater.loadAnimator(this, R.animator.value_animator);
mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mTarget.setY((Float) animation.getAnimatedValue());
}
});
mValueAnimator.start();
通過代碼實作
語法:
ValueAnimator valueAnimator = ValueAnimator.ofFloat(float... values);
valueAnimator.setDuration(long duration);
valueAnimator.setInterpolator(TimeInterpolator value);
valueAnimator.addUpdateListener(AnimatorUpdateListener listener);
…
valueAnimator.start();
示例:
ValueAnimator mValueAnimator = ValueAnimator.ofFloat(0, 800);
mValueAnimator.setDuration(1800);
mValueAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
mValueAnimator.setRepeatCount(ValueAnimator.INFINITE);
mValueAnimator.setRepeatMode(ValueAnimator.REVERSE);
mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mTarget.setY((Float) animation.getAnimatedValue());
}
});
mValueAnimator.start();
ObjectAnimator
要影片顯示 View 物件的某個屬性,比如顏色或旋轉值,我們所有要做的事情就是創建一個 Property animation,并設定對應的 View 屬性,那接下來我們就用ObjectAnimator類來分別實作View的透明度漸變、收縮、移動和旋轉等影片效果,那在此之前我們也來總結下使用ObjectAnimator實作影片的幾個步驟,如下:
- 通過呼叫ofFloat()、ofInt()等方法創建ObjectAnimator物件,并設定目標物件、需要改變的目標屬性名、初始值和結束值;
- 設定影片的持續時間、是否重復及重復次數等屬性;
- 啟動影片,
常用的幾個屬性值解釋:
- translationX 和 translationY:這兩個屬性控制著 View 的螢屏位置坐標變化量,以 layout 容器的左上角為坐標原點;
- rotation、rotationX 和 rotationY:這三個屬性控制著 2D 旋轉角度(rotation屬性)和圍繞某樞軸點的 3D 旋轉角度;
- scaleX、scaleY:這兩個屬性控制著 View 圍繞某樞軸點的 2D 縮放比例;
- pivotX 和 pivotY: 這兩個屬性控制著樞軸點的位置,前述的旋轉和縮放都是以此點為中心展開的,預設的樞軸點是 View 物件的中心點;
- x 和 y:這是指 View 在容器內的最終位置,等于 View 左上角相對于容器的坐標加上 translationX 和 translationY 后的值;
- alpha:表示 View 的 alpha 透明度,預設值為 1 (不透明),為 0 則表示完全透明(看不見);
通過XML創建
語法:
<objectAnimator
xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="int"
android:interpolator="@[package:]anim/interpolator_resource"
android:propertyName="string"
android:valueType=["intType" | "floatType"]
android:valueFrom="float | int | color"
android:valueTo="float | int | color"
android:startOffset="int"
android:repeatCount="int"
android:repeatMode=["repeat" | "reverse"]
/>

示例:
//1. 創建 object_animator.xml
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1800"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:propertyName="Y"
android:valueType="floatType"
android:valueFrom="0"
android:valueTo="800"
android:startOffset="0"
android:repeatCount="infinite"
android:repeatMode="reverse"
/>
//2. 在代碼中使用 object_animator
ObjectAnimator mObjectAnimator = (ObjectAnimator) AnimatorInflater.loadAnimator(this, R.animator.object_animator);
mObjectAnimator.setTarget(mTarget);
mObjectAnimator.start();
通過代碼實作
語法:
ObjectAnimator objectAnimator = ObjectAnimator.ofObject(Object target, String propertyName, TypeEvaluator evaluator, Object... values);
objectAnimator.setDuration(long duration);
objectAnimator.setInterpolator(TimeInterpolator value);
…
objectAnimator.start();
示例:
ObjectAnimator mObjectAnimator = ObjectAnimator.ofFloat(mTarget, "y", 0, 800);
mObjectAnimator.setDuration(1800);
mObjectAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
mObjectAnimator.setRepeatCount(ValueAnimator.INFINITE);
mObjectAnimator.setRepeatMode(ValueAnimator.REVERSE);
mObjectAnimator.start();
AnimatorSet
通過XML創建
語法:
<set
xmlns:android="http://schemas.android.com/apk/res/android"
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>

示例:
//1. 創建 animator_set.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="together"
>
<objectAnimator
android:duration="@integer/integer_one_thousand_and_eight_hundred"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:propertyName="Y"
android:valueType="floatType"
android:valueFrom="0"
android:valueTo="800"
android:startOffset="0"
android:repeatCount="infinite"
android:repeatMode="reverse"
/>
<objectAnimator
android:duration="@integer/integer_one_thousand_and_eight_hundred"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:propertyName="ScaleX"
android:valueType="floatType"
android:valueFrom="1"
android:valueTo="2"
android:startOffset="0"
android:repeatCount="infinite"
android:repeatMode="reverse"
/>
<objectAnimator
android:duration="@integer/integer_one_thousand_and_eight_hundred"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:propertyName="ScaleY"
android:valueType="floatType"
android:valueFrom="1"
android:valueTo="2"
android:startOffset="0"
android:repeatCount="infinite"
android:repeatMode="reverse"
/>
</set>
//2. 在代碼中使用 animator_set
AnimatorSet mAnimatorSet = (AnimatorSet)AnimatorInflater.loadAnimator(this, R.animator.animator_set);
mAnimatorSet.setTarget(mTarget);
mAnimatorSet.start();
通過代碼實作
語法:
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(Animator... items);
animatorSet.playSequentially(Animator... items);
//非必須
animatorSet.setTarget(mTarget);
…
animatorSet.start();
示例:
ObjectAnimator translateYObjectAnimator = ObjectAnimator.ofFloat(mTarget, "y", 0, 800);
translateYObjectAnimator.setDuration(1800);
translateYObjectAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
translateYObjectAnimator.setRepeatCount(ValueAnimator.INFINITE);
translateYObjectAnimator.setRepeatMode(ValueAnimator.REVERSE);
ObjectAnimator scaleXObjectAnimator = ObjectAnimator.ofFloat(mTarget, "scaleX", 1, 2);
scaleXObjectAnimator.setDuration(1800);
scaleXObjectAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
scaleXObjectAnimator.setRepeatCount(ValueAnimator.INFINITE);
scaleXObjectAnimator.setRepeatMode(ValueAnimator.REVERSE);
ObjectAnimator scaleYObjectAnimator = ObjectAnimator.ofFloat(mTarget, "scaleY", 1, 2);
scaleYObjectAnimator.setDuration(1800);
scaleYObjectAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
scaleYObjectAnimator.setRepeatCount(ValueAnimator.INFINITE);
scaleYObjectAnimator.setRepeatMode(ValueAnimator.REVERSE);
mAnimatorSet = new AnimatorSet();
mAnimatorSet.playTogether(translateYObjectAnimator, scaleXObjectAnimator, scaleYObjectAnimator);
mAnimatorSet.playSequentially();
//非必須
// mAnimatorSet.setTarget(mTarget);
mAnimatorSet.start();
監聽屬性影片
Property Animation 中一共有三種監聽事件:
- AnimatorListener;
- AnimatorPauseListener;
- AnimatorUpdateListener;
AnimatorListener
AnimatorListener 介面主要用于監聽 Property Animation 的開始、結束、取消、重復狀態,需要實作的方法分別是:
@Override
public void onAnimationStart(Animator animation) {}
@Override
public void onAnimationEnd(Animator animation) {}
@Override
public void onAnimationCancel(Animator animation) {}
@Override
public void onAnimationRepeat(Animator animation) {}
AnimatorPauseListener
AnimatorPauseListener 主要用于監聽 Property Animation 的暫停、恢復狀態,需要實作的方法分別是:
@Override
public void onAnimationPause(Animator animation) {}
@Override
public void onAnimationResume(Animator animation) {}
AnimatorUpdateListener
AnimatorUpdateListener 是 ValueAnimator 及其子類特有的介面,主要用于監聽影片中值的變化,用于手動更新界面,需要實作的方法是:
@Override
public void onAnimationUpdate(ValueAnimator animation) {}
屬性影片作業原理
當 ValueAnimator 呼叫 start 方法之后,ValueAnimator 會根據 Property Animation 當前運行時間與總的影片持續時間計算出一個時間消耗百分數(The elapsed fraction),緊接著,ValueAnimator 將這個時間消耗百分數交給當前 ValueAnimator 的插值器(Interpolator),不同的 Interpolator 會根據不同的演算法將這個時間消耗百分數轉換成插值百分數(The interpolated fraction),緊接著,ValueAnimator 會將這個插值百分數交給當前 ValueAnimator 的估值器(TypeEvaluator),不同的 TypeEvaluator 會根據不同的演算法將這個插值百分數轉換最終的影片值(The final value),
拿AccelerateDecelerateInterpolator插值器舉例:
public class AccelerateDecelerateInterpolator extends BaseInterpolator
implements NativeInterpolatorFactory {
public AccelerateDecelerateInterpolator() {
}
@SuppressWarnings({"UnusedDeclaration"})
public AccelerateDecelerateInterpolator(Context context, AttributeSet attrs) {
}
/**
* param input (The elapsed fraction)
* return (The interpolated fraction)
*/
public float getInterpolation(float input) {
return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}
/** @hide */
@Override
public long createNativeInterpolator() {
return NativeInterpolatorFactoryHelper.createAccelerateDecelerateInterpolator();
}
}

上面這個屬性影片的 Duration 為 40ms,Intepolator 為 AccelerateDecelerateInterpolator,Distance 為 40,
在 t = 10ms 時,The elapsed fraction 為 0.25 = 10/40,The interpolated fraction = (float)(Math.cos((0.25 + 1) * Math.PI) / 2.0f) + 0.5f = 0.14644662,The final value 為 5.8578648 = (40 - 0) * 0.14644662,
自定義插值器
自定義插值器要實作 Interpolator 介面,上篇文章已經有所說明,不做過多闡述,
public class DecelerateAccelerateInterpolator implements Interpolator {
@Override
public float getInterpolation(float input) {
return (float) ((Math.tan(Math.PI/2 * input - Math.PI/4) + 1)/2);
}
}
自定義估值器
自定義估值器,只要實作 TypeEvaluator 介面,并實作其中定義的 evaluate 方法即可:
public class CustomTypeEvaluator implements TypeEvaluator {
/**
* param fraction 插值器最終值
* param startValue 屬性開始值
* param endValue 屬性結束值
*/
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
float startFloat = ((Number) startValue).floatValue();
return 200 + fraction * (((Number) endValue).floatValue() - startFloat);
}
}
ViewPropertyAnimator 使用簡介
ViewPropertyAnimator、ObjectAnimator、ValueAnimator 這三種 Animator,它們其實是一種遞進的關系:從左到右依次變得更加難用,也更加靈活,
它們的性能是一樣的,因為 ViewPropertyAnimator 和 ObjectAnimator 的內部實作其實都是 ValueAnimator,ObjectAnimator 更是本來就是 ValueAnimator 的子類,它們三個的性能并沒有差別,
它們的差別只是使用的便捷性以及功能的靈活性,所以在實際使用時候的選擇,只要遵循一個原則就行:盡量用簡單的,能用 View.animate() 實作就不用 ObjectAnimator,能用 ObjectAnimator 就不用 ValueAnimator,
當需要同時更改 View 的多個屬性的時候,一般有三種方法:
- ObjectAnimator + AnimatorSet;
- PropertyValuesHolder + ObjectAnimator;
- ViewPropertyAnimator;
接下來,分別用三種方法分別實作同一種效果:View 的 Y 值從當前位置增到 400,Alpha 值 從 1.0f 變成 0.1f,
ObjectAnimator + AnimatorSet
ObjectAnimator alphaObjectAnimator = ObjectAnimator.ofFloat(mTarget, "alpha", 1.0f, 0.1f);
ObjectAnimator yObjectAnimator = ObjectAnimator.ofFloat(mTarget, "y", 400f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(alphaObjectAnimator, yObjectAnimator);
animatorSet.start();
PropertyValuesHolder + ObjectAnimator
PropertyValuesHolder alphaPropertyValuesHolder = PropertyValuesHolder.ofFloat("alpha", 1.0f, 0.1f);
PropertyValuesHolder yPropertyValuesHolder = PropertyValuesHolder.ofFloat("y", 400f);
ObjectAnimator.ofPropertyValuesHolder(mTarget, alphaPropertyValuesHolder, yPropertyValuesHolder).start();
ViewPropertyAnimator
ViewPropertyAnimator viewPropertyAnimator = mTarget.animate();
viewPropertyAnimator.alpha(0.1f);
viewPropertyAnimator.y(400f);
//也可以寫成一句:
mTarget.animate().alpha(0.1f).y(400f);
PropertyValuesHolder
細心的同學可能會注意到,ValueAnimator、ObjectAnimator除了這些創建Animator實體的方法以外,都還有一個方法:
/**
* valueAnimator的
*/
public static ValueAnimator ofPropertyValuesHolder(PropertyValuesHolder... values)
/**
* ObjectAnimator的
*/
public static ObjectAnimator ofPropertyValuesHolder(Object target,PropertyValuesHolder... values)
PropertyValuesHolder這個類的意義就是,它其中保存了影片程序中所需要操作的屬性和對應的值,我們通過ofFloat(Object target, String propertyName, float… values)構造的影片,ofFloat()的內部實作其實就是將傳進來的引數封裝成PropertyValuesHolder實體來保存影片狀態,在封裝成PropertyValuesHolder實體以后,后期的各種操作也是以PropertyValuesHolder為主的,
使用舉例:
PropertyValuesHolder rotationHolder = PropertyValuesHolder.ofFloat("Rotation", 60f, -60f, 40f, -40f, -20f, 20f, 10f, -10f, 0f);
PropertyValuesHolder colorHolder = PropertyValuesHolder.ofInt("BackgroundColor", 0xffffffff, 0xffff00ff, 0xffffff00, 0xffffffff);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(mTextView, rotationHolder, colorHolder);
animator.setDuration(3000);
animator.setInterpolator(new AccelerateInterpolator());
animator.start();
參考
- https://developer.android.com/reference/android/animation/Animator
- https://carsonho.blog.csdn.net/article/details/72909894
- https://blog.csdn.net/harvic880925/article/details/50752838
- https://juejin.cn/post/6844903798687678478#heading-34
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/265428.html
標籤:其他
