原文首發於微信公衆號:jzman-blog,歡迎關注交流!php
屬性動畫相較幀動畫和補間動畫更強大,幀動畫和補間動畫只能應用於 View 及其子類,而屬性動畫能夠修改任何對象的屬性值,屬性值可在指定的一段時間內自動改變,根據對象屬性值的變化進而實現更復雜的動畫。java
下面是屬性動畫的經常使用設置,具體以下:android
//設置屬性動畫持續時間
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 提供了一個簡單的計時引擎,用於執行動畫時根據設置的時長以及其餘屬相完成動畫值的計算,而後就能夠將動畫值設置到合適的目標對象上,使用的插值器默認時 AccelerateDecelerateInterpolator,表示動畫開始和結束時較慢,中間加速完成動畫,下面是源碼中默認的插值器,具體以下:bash
// 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 這個類中,具體以下:微信
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 的使用方式,其餘如縮放、旋轉等使用方式相似。ide
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();
}
複製代碼
在 res/animator 文件夾下建立 test_animator.xml 文件,文件內容以下:學習
<?xml version="1.0" encoding="utf-8"?>
<animator xmlns:android="http://schemas.android.com/apk/res/android" android:valueFrom="0" android:valueTo="100" android:valueType="intType" android:duration="2000" android:startOffset ="0" android:repeatMode = "reverse" android:repeatCount = "0" android:interpolator = "@android:anim/accelerate_interpolator">
</animator>
複製代碼
而後在 Activity 中獲取 ValueAnimator,設置目標對象,啓動動畫便可,具體以下:測試
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 來實現平移動畫,測試效果以下:動畫
ObjectAnimator 是 ValueAnimator 的子類,可在目標對象上支持動畫屬性的設置,在其構造方法中經過參數指定目標對象以及所對應動畫屬性的名稱,而後會相應的執行對應的動畫屬性的 setter 方法來最終完成動畫的執行,也就是說屬性動畫 ObjectAnimator 最終調用目標對象的 setter 方法完成目標對象屬性值的變化,而後相應的改變目標對象的屬性,從而實現目標對象的動畫效果,下面以透明度變化來介紹 ObjectAnimator 的基本使用,代碼參考以下:ui
private void alpha(){
ObjectAnimator animator = ObjectAnimator.ofFloat(ivImage,"alpha",1f,0,1f);
animator.setDuration(3000);
//其餘屬性動畫設置
//...
animator.start();
}
複製代碼
下面是測試效果,以下圖所示:
至於平移、旋轉、縮放動畫實現方式基本如上,這裏再也不贅述,其對應的 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() 方法來方面設置屬性動畫,以下圖所示:
可根據不一樣的動畫需求使用 ObjectValueAnimator 不一樣 ofXxx() 方法來實現相應的動畫。
這裏簡單說一下關鍵幀的使用,顧名思義關鍵幀就是在某個固定時刻上定義具體的屬性值,爲定義的將按照估值器返回的值返回屬性值,屬性動畫中的關鍵幀使用方式以下:
/** * 關鍵幀的使用 */
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();
}
複製代碼
看一下添加關鍵幀以後對普通平移動畫的改變,實現測試效果以下:
Android 內置許多插值器,這些插值器基本涵蓋了實際開發中的大部分狀況,具體以下:
若是內置的插值器不知足需求,也能夠自定義插值器。
這裏自定義一個估值器來實現一個 View 沿正弦曲線運動,自定義估值器以下:
/** * 自定義估值器 * Point封裝了座標x和y */
public class SineTypeValue implements TypeEvaluator<Point> {
@Override
public Point evaluate(float fraction, Point startValue, Point endValue) {
//y = sinA
float distance = fraction * (endValue.getX() - startValue.getX());
float x = startValue.getX() + distance;
float y = startValue.getY() + (float) Math.sin(distance / 100 * Math.PI) * 100;
Point point = new Point();
point.setX(x);
point.setY(y);
return point;
}
}
複製代碼
而後給動畫設置該估值器,監聽動畫屬性設置 View 的位置便可實現一個 View 沿正弦曲線運動,使用方式以下:
/**
* 自定義估值器的使用
* 正弦運動的估值器
*/
private void sina(){
Point startPoint = new Point(ivImage.getX(),ivImage.getY());
Point endPoint = new Point(ivImage.getX()+500,ivImage.getY());
ValueAnimator valueAnimator = ValueAnimator.ofObject(new SineTypeValue(), startPoint, endPoint);
valueAnimator.setDuration(5000);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Log.i(TAG, animation.getAnimatedValue() + "");
Point point = (Point) animation.getAnimatedValue();
ivImage.setX(point.getX());
ivImage.setY(point.getY());
}
});
valueAnimator.start();
}
複製代碼
測試效果以下:
以關注公衆號:零點小築(jzman-blog),一塊兒交流學習。