Android動畫系列之屬性動畫
阿新 • • 發佈:2020-12-02
> 原文首發於微信公眾號:jzman-blog,歡迎關注交流!
屬性動畫相較幀動畫和補間動畫更強大,幀動畫和補間動畫只能應用於 View 及其子類,而屬性動畫可以修改任何物件的屬性值,屬性值可在指定的一段時間內自動改變,根據物件屬性值的變化進而實現更復雜的動畫。
1. 屬性動畫的常用設定
2. ValueAnimator
3. ObjectAnimator
4. 關鍵幀
5. 插值器和估值器
#### 屬性動畫的常用設定
下面是屬性動畫的常用設定,具體如下:
```java
//設定屬性動畫持續時間
animator.setDuration(2000);
//設定屬性插值器
animator.setInterpolator(new AccelerateInterpolator());
//設定屬性動畫重複播放模式
animator.setRepeatMode(ValueAnimator.REVERSE);
//設定屬性動畫重複播放次數
animator.setRepeatCount(0);
//設定屬性動畫延時播放的時間
animator.setStartDelay(0);
//設定屬性動畫估值器,用於控制最終屬性值(API22)
animator.setCurrentFraction(0.5f);
//設定當前播放時間,其值在Duration範圍之內
animator.setCurrentPlayTime(1000);
//設定屬性動畫估值器,用於控制最終屬性值
animator.setEvaluator(new IntEvaluator());
//設定屬性動畫監聽
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Log.i(TAG, animation.getAnimatedValue() + "");
//
}
});
//...
```
#### ValueAnimator
ValueAnimator 提供了一個簡單的計時引擎,用於執行動畫時根據設定的時長以及其他屬相完成動畫值的計算,然後就可以將動畫值設定到合適的目標物件上,使用的插值器預設時 AccelerateDecelerateInterpolator,表示動畫開始和結束時較慢,中間加速完成動畫,下面是原始碼中預設的插值器,具體如下:
```java
// The time interpolator to be used if none is set on the animation
private static final TimeInterpolator sDefaultInterpolator =
new AccelerateDecelerateInterpolator();
```
在 ValueAnimator 中已經內部處理了一些估值器 IntEvaluator 和 FloatEvaluator,也就是說如果使用的時 ofInt 和 ofFloat 方法作為動畫的屬性值,那麼 ValueAnimator 會自動處理 int 和 float 值的變化,在原始碼中找了一下,這部分內容在 PropertyValuesHolder 這個類中,具體如下:
```java
void init() {
if (mEvaluator == null) {
// We already handle int and float automatically, but not their Object
// equivalents
mEvaluator = (mValueType == Integer.class) ? sIntEvaluator :
(mValueType == Float.class) ? sFloatEvaluator :
null;
}
if (mEvaluator != null) {
// KeyframeSet knows how to evaluate the common types - only give it a custom
// evaluator if one has been set on this class
mKeyframes.setEvaluator(mEvaluator);
}
}
```
ValueAnimator 可以使用程式碼建立,也可以使用 xml 建立,下面以平移動畫為例說明 ValueAnimator 的使用方式,其他如縮放、旋轉等使用方式類似。
##### 使用程式碼建立
```java
private void translation(){
ValueAnimator valueAnimator = ValueAnimator.ofInt(0, 100);
valueAnimator.setDuration(2000);
valueAnimator.setInterpolator(new AccelerateInterpolator());
valueAnimator.setRepeatMode(ValueAnimator.REVERSE);
valueAnimator.setRepeatCount(0);
valueAnimator.setStartDelay(0);
// valueAnimator.setCurrentFraction(0.5f);
// valueAnimator.setCurrentPlayTime(1000);
valueAnimator.setEvaluator(new IntEvaluator());
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Log.i(TAG, animation.getAnimatedValue() + "");
int x = (int) animation.getAnimatedValue();
ivImage.setTranslationX(x);
ivImage.setTranslationY(x);
}
});
valueAnimator.start();
}
```
##### 使用xml建立
在 res/animator 資料夾下建立 test_animator.xml 檔案,檔案內容如下:
```xml
```
然後在 Activity 中獲取 ValueAnimator,設定目標物件,啟動動畫即可,具體如下:
```java
private void translation(){
ValueAnimator animator = (ValueAnimator) AnimatorInflater.loadAnimator(this,R.animator.test_animator);
animator.setTarget(ivImage);
animator.start();
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Log.i(TAG, animation.getAnimatedValue() + "");
int x = (int) animation.getAnimatedValue();
ivImage.setTranslationX(x);
ivImage.setTranslationY(x);
}
});
}
```
##### 測試效果
這裡使用 ValueAnimator 來實現平移動畫,測試效果如下:
![ValueAnimator](https://user-gold-cdn.xitu.io/2019/9/21/16d544e11faa91a9?w=354&h=434&f=gif&s=49881)
#### ObjectAnimator
ObjectAnimator 是 ValueAnimator 的子類,可在目標物件上支援動畫屬性的設定,在其構造方法中通過引數指定目標物件以及所對應動畫屬性的名稱,然後會相應的執行對應的動畫屬性的 setter 方法來最終完成動畫的執行,也就是說屬性動畫 ObjectAnimator 最終呼叫目標物件的 setter 方法完成目標物件屬性值的變化,然後相應的改變目標物件的屬性,從而實現目標物件的動畫效果,下面以透明度變化來介紹 ObjectAnimator 的基本使用,程式碼參考如下:
```
private void alpha(){
ObjectAnimator animator = ObjectAnimator.ofFloat(ivImage,"alpha",1f,0,1f);
animator.setDuration(3000);
//其他屬性動畫設定
//...
animator.start();
}
```
下面是測試效果,如下圖所示:
![屬性動畫-透明度](https://user-gold-cdn.xitu.io/2019/9/21/16d544e11f436579?w=385&h=330&f=gif&s=89466)
至於平移、旋轉、縮放動畫實現方式基本如上,這裡不再贅述,其對應的 setter 方法對應關係如下:
屬性|作用|對應方法
---|---|---
Alpha|控制View的透明度|setAlpha
TranslationX|控制X方向的位移|setTranslationX
TranslationY|控制Y方向的位移|setTranslationY
ScaleX|控制X方向的縮放倍數|setScaleX
ScaleY|控制Y方向的縮放倍數|setScaleY
Rotation|控制以螢幕方向為軸的旋轉度數|setRotation
RotationX|控制以X軸為軸的旋轉度數|setRotationX
RotationY|控制以Y軸為軸的旋轉度數|setRotationY
ObjectAnimator 提供了很多的 ofXxx() 方法來方面設定屬性動畫,如下圖所示:
![屬性動畫-ofXxx()](https://user-gold-cdn.xitu.io/2019/9/21/16d544e11fb107ed?w=1161&h=652&f=jpeg&s=112262)
可根據不同的動畫需求使用 ObjectValueAnimator 不同 ofXxx() 方法來實現相應的動畫。
#### 關鍵幀
這裡簡單說一下關鍵幀的使用,顧名思義關鍵幀就是在某個固定時刻上定義具體的屬性值,為定義的將按照估值器返回的值返回屬性值,屬性動畫中的關鍵幀使用方式如下:
```java
/**
* 關鍵幀的使用
*/
private void keyFrame(){
Keyframe keyframe1 = Keyframe.ofFloat(0,0);
Keyframe keyframe2 = Keyframe.ofFloat(0.25f,300);
//每個KeyFrame可設定自己的插值器
keyframe2.setInterpolator(new AccelerateInterpolator());
Keyframe keyframe3 = Keyframe.ofFloat(0.75f,100);
Keyframe keyframe4 = Keyframe.ofFloat(1,400);
PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("translationX",keyframe1,keyframe2,keyframe3,keyframe4);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(ivImage,holder);
animator.setDuration(3000);
animator.start();
}
```
看一下新增關鍵幀之後對普通平移動畫的改變,實現測試效果如下:
![keyFragme.gif](https://user-gold-cdn.xitu.io/2019/9/21/16d544e11f5709b9?w=386&h=328&f=gif&s=117675)
#### 插值器和估值器
- 插值器(TimeInterpolator) 表示的是整個動畫期間動畫的變化規律,如加速、減速等。
Android 內建許多插值器,這些插值器基本涵蓋了實際開發中的大部分情況,具體如下:
![插值器](https://user-gold-cdn.xitu.io/2019/9/21/16d544e11f0afd5f?w=926&h=444&f=png&s=82857)
如果內建的插值器不滿足需求,也可以自定義插值器。
- 估值器(TypeEvaluator)表示的是在整個動畫期間各時刻屬性值的具體變化。
這裡自定義一個估值器來實現一個 View 沿正弦曲線運動,自定義估值器如下:
```java
/**
* 自定義估值器
* Point封裝了座標x和y
*/
public class SineTypeValue implements TypeE