在上一篇文章《Android屬性動畫(一) 初識基本用法》中,我們學習了屬性動畫的基本用法,但是在一些場景中,這些用法還遠不能滿足我們的需求,今天就讓我們來學習一下屬性動畫的高級用法吧!
1.ValueAnimator的實際應用
在上篇文章中我們學習到,ValueAnimator.ofInt()方法可以幫我們計算初始值到結束值之間的動畫過渡值,但是這些值如何應用到實際的View中呢,舉個簡單的例子來實踐一下,先上張圖:
可以看到圖中有一個六邊形的雷達圖,六個角分別代表六種監控業務,每個角有一個白色的圓點,代表此項監控業務正常,現在有這樣一個需求,當其中一項監控業務報警的時候,白色的圓點變成閃爍的黃點,同時背景變成紅色。背景變色這個很容易,直接給佈局設置一下背景顏色就可以了,我們來實現一下閃爍的黃點這個效果。
// 是否正在播放動畫
private boolean isAnimationPlaying = false;
/**
* 繪製點
*
* @param canvas 畫布
*/
private void drawPoints(Canvas canvas) {
for (int i = 0; i < dataCount; i++) {
if (deviceStatus[i] == ONLINE) {
pointPaint.setColor(Color.WHITE);
pointPaint.setAlpha(255);
canvas.drawCircle(getPoint(i).x, getPoint(i).y, dp2px(3), pointPaint);
} else if (deviceStatus[i] == ALARM) {
pointPaint.setColor(Color.WHITE);
pointPaint.setAlpha(255);
canvas.drawCircle(getPoint(i).x, getPoint(i).y, dp2px(3), pointPaint);
if (!isAnimationPlaying) {
isAnimationPlaying = true;
ValueAnimator animator = ValueAnimator.ofInt(0, 100);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int currentValue = (int) animation.getAnimatedValue();
// 給報警點設置0至100的透明度
alarmPointPaint.setAlpha(currentValue);
invalidate();
}
});
// 單次動畫時長1.5s
animator.setDuration(1500);
// 無限循環播放動畫
animator.setRepeatCount(ValueAnimator.INFINITE);
// 循環時倒序播放
animator.setRepeatMode(ValueAnimator.REVERSE);
animator.start();
} else {
canvas.drawCircle(getPoint(i).x, getPoint(i).y, dp2px(8), alarmPointPaint);
}
}
}
}
當監控狀態爲ONLINE的時候繪製白色圓點,報警的時候先判斷一下當前是否正在播放動畫,如果沒有播放,初始化ValueAnimator並設置一個監聽器,通過給畫筆設置0到100的透明度的方式來實現閃爍效果,動畫播放模式設置成了無限循環,如果消除報警,不要忘了調用ValueAnimator的cancel方法來結束動畫,完整的代碼已上傳到GitHub上,如果感興趣可以下載下來看看,OK,運行一下程序看下效果:
2.自定義TypeEvaluator
先了解下TypeEvaluator是什麼,TypeEvaluator可以翻譯成估值器,用於計算動畫從開始到結束的過渡值,前面說過ValueAnimator.ofInt()方法可以幫助我們實現初始值到結束值之間的平滑過度,其實它的內部就是通過IntEvaluator來完成計算的,而IntEvaluator就是繼承於TypeEvaluator,看下IntEvaluator類:
public class IntEvaluator implements TypeEvaluator<Integer> {
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
int startInt = startValue;
return (int)(startInt + fraction * (endValue - startInt));
}
}
可以看到IntEvaluator實現了TypeEvaluator接口,重寫了evaluate方法,傳入了三個參數,第一個參數非常重要,代表當前動畫的完成度,第二個和第三個參數分別代表動畫的開始值和結束值,結束值減去開始值然後乘以動畫完成度,再加上開始值就可以得到當前動畫的值了。
我們已經使用過了ValueAnimator的ofFloat和ofInt方法,其中已經內置了FloatEvaluator和IntEvaluator來用於過渡值的計算,ValueAnimator還有一個ofObject方法,可以對任意對象進行動畫操作,這就需要我們自己來定義一個估值器,告訴系統如何進行動畫過渡。
現在有這樣一個需求,監控業務報警之後背景顏色從藍色到紅色的變化有些生硬,我們需要一個2s的顏色過渡動畫,由於是直接操作View,這裏我們使用 ObjectAnimator.ofObject()來實現這樣一效果。
在上篇文章中我們學習到,ObjectAnimator內部的工作原理就是通過在View中查找屬性名對應的get、set方法來設置對應的屬性值的,因此我們需要自定義一個ColorView控件,定義一個backgroundColor屬性,並提供它的get和set方法。
public class ColorView extends RelativeLayout {
private String backgroundColor;
public ColorView(Context context) {
this(context, null);
}
public ColorView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ColorView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public String getBackgroundColor() {
return backgroundColor;
}
public void setBackgroundColor(String backgroundColor) {
this.backgroundColor = backgroundColor;
this.setBackgroundColor(Color.parseColor(backgroundColor));
}
}
定義一個ColorEvaluator類來計算顏色的過渡值:
public class ColorEvaluator implements TypeEvaluator {
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
String startColor = (String) startValue;
String endColor = (String) endValue;
int startRed = Integer.parseInt(startColor.substring(1, 3), 16);
int startGreen = Integer.parseInt(startColor.substring(3, 5), 16);
int startBlue = Integer.parseInt(startColor.substring(5, 7), 16);
int endRed = Integer.parseInt(endColor.substring(1, 3), 16);
int endGreen = Integer.parseInt(endColor.substring(3, 5), 16);
int endBlue = Integer.parseInt(endColor.substring(5, 7), 16);
int currentRed = (int) ((endRed - startRed) * fraction + startRed);
int currentGreen = (int) ((endGreen - startGreen) * fraction + startGreen);
int currentBlue = (int) ((endBlue - startBlue) * fraction + startBlue);
return "#" + getHexString(currentRed) + getHexString(currentGreen) + getHexString(currentBlue);
}
private String getHexString(int value) {
String hexString = Integer.toHexString(value);
if (hexString.length() == 1) {
hexString = "0" + hexString;
}
return hexString;
}
}
在佈局文件中使用ColorView:
<?xml version="1.0" encoding="utf-8"?>
<com.yl.propertyanimationdemo.widget.ColorView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/rl_device_status"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#2B93EC">
<com.yl.propertyanimationdemo.widget.RadarView
android:id="@+id/rv_device_status"
android:layout_width="250dp"
android:layout_height="230dp"
android:layout_centerInParent="true" />
<Button
android:id="@+id/btn_alarm"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="20dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:background="#00000000"
android:text="報警"
android:textColor="#FFF"
android:textSize="20sp" />
</com.yl.propertyanimationdemo.widget.ColorView>
設置顏色過渡動畫:
// 顏色過渡動畫
ObjectAnimator animator = ObjectAnimator.ofObject(rlDeviceStatus, "backgroundColor",
new ColorEvaluator(), "#2B93EC", "#ED6E74");
animator.setDuration(2000);
animator.start();
看下效果:
3.寫在最後
源碼已託管到GitHub上,歡迎Fork,覺得還不錯就Start一下吧!
GitHub地址:https://github.com/alidili/PropertyAnimationDemo
歡迎同學們吐槽評論,如果你覺得本篇博客對你有用,那麼就留個言或者頂一下吧(^-^)