動(dòng)畫分類
補(bǔ)間動(dòng)畫
旋轉(zhuǎn)咽瓷、位移崔挖、透明度贸街、縮放
屬性動(dòng)畫
同樣的屬性動(dòng)畫也可以做到對(duì)View進(jìn)行縮放、移動(dòng)狸相、旋轉(zhuǎn)以及改變透明度;除此以外,它還能改變對(duì)象的某個(gè)屬性薛匪。
ObjectAnimator.ofFloat()
ValueAnimator.start()
ObjectAnimator繼承于ValueAnimator
public void start() {
start(false);
}
private void start(boolean playBackwards) {
if (Looper.myLooper() == null) {
throw new AndroidRuntimeException("Animators may only be run on Looper threads");
}
//省略部分代碼...
//為動(dòng)畫添加回調(diào)
addAnimationCallback(0);
//判斷動(dòng)畫開始時(shí)間是否需要延遲
if (mStartDelay == 0 || mSeekFraction >= 0 || mReversing) {
startAnimation();
if (mSeekFraction == -1) {
setCurrentPlayTime(0);
} else {
setCurrentFraction(mSeekFraction);
}
}
}
addAnimationCallback(0);
這里調(diào)用了AnimationHandler類的addAnimationFrameCallback(),最終會(huì)調(diào)用doAnimationFrame方法
private void doAnimationFrame(long frameTime) {
long currentTime = SystemClock.uptimeMillis();
final int size = mAnimationCallbacks.size();
for (int i = 0; i < size; i++) {
final AnimationFrameCallback callback = mAnimationCallbacks.get(i);
if (callback == null) {
continue;
}
if (isCallbackDue(callback, currentTime)) {
callback.doAnimationFrame(frameTime);
if (mCommitCallbacks.contains(callback)) {
getProvider().postCommitCallback(new Runnable() {
@Override
public void run() {
commitAnimationFrame(callback, getProvider().getFrameTime());
}
});
}
}
}
cleanUpList();
}
將一個(gè)callback丟到Choreographer中,當(dāng)下一個(gè)Vsync信號(hào)來時(shí)執(zhí)行doAnimationFrame()
/**
* Callbacks that receives notifications for animation timing and frame commit timing.
*/
interface AnimationFrameCallback {
boolean doAnimationFrame(long frameTime);
void commitAnimationFrame(long frameTime);
}
doAnimationFrame()中會(huì)執(zhí)行到animateValue()
void animateValue(float fraction) {
fraction = mInterpolator.getInterpolation(fraction);
mCurrentFraction = fraction;
int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
mValues[i].calculateValue(fraction);
}
if (mUpdateListeners != null) {
int numListeners = mUpdateListeners.size();
for (int i = 0; i < numListeners; ++i) {
mUpdateListeners.get(i).onAnimationUpdate(this);
}
}
}
mInterpolator就是插值器TimeInterpolator脓鹃、TimeInterpolator接口提供了一個(gè)方法getInterpolation()獲取當(dāng)前屬性隨時(shí)間變化的百分比
public interface TimeInterpolator {
float getInterpolation(float input);
}
mValues[i].calculateValue(fraction);會(huì)調(diào)用估值器逸尖,將插值器計(jì)算出的值作為輸入,計(jì)算出要變化的值設(shè)置給屬性
public interface TypeEvaluator<T> {
public T evaluate(float fraction, T startValue, T endValue);
}
startAnimation()
startAnimation()會(huì)調(diào)用ininAnimation()方法而ObjectAnimation重寫了該方法
void initAnimation() {
if (!mInitialized) {
final Object target = getTarget();
if (target != null) {
final int numValues = mValues.length;
for (int i = 0; i < numValues; ++i) {
mValues[i].setupSetterAndGetter(target);
}
}
super.initAnimation();
}
}
mValues為PropertyValuesHolder類型,從這可以看出調(diào)用了PropertyValuesHolder的setupSetterAndGetter方法,這個(gè)方法中查找了相對(duì)應(yīng)屬性的set/get方法冷溶。最終會(huì)調(diào)用 getPropertyFunction()方來獲取相應(yīng)的方法,若通過反射沒有獲取到相應(yīng)的set/get方法時(shí)就會(huì)拋出 NoSuchMethodException異常
private Method getPropertyFunction(Class targetClass, String prefix, Class valueType) {
// TODO: faster implementation...
Method returnVal = null;
//prefix表示set或get,然后在通過getMethodName()方法拼接出相應(yīng)的方法名
String methodName = getMethodName(prefix, mPropertyName);
Class args[] = null;
//省略部分代碼
returnVal = targetClass.getMethod(methodName, args);
return returnVal;
//省略部分代碼
}
因?yàn)槲覀冃枰獙?duì)View的translationX屬性進(jìn)行設(shè)置,所以通過這里可以看出我們?cè)O(shè)置屬性時(shí)是通過View.setTranslationX()方法來設(shè)置的渐白。
Choreographer
Choreographer是動(dòng)畫原理的一個(gè)核心,搞明白動(dòng)畫工作原理之前我們需要先了解Choreographer工作過程逞频;
Choreographer工作過程簡單描述如下:在Choreographer對(duì)象中有四條鏈表宗收,分別保存著待處理的輸入事件升敲,待處理的動(dòng)畫事件,待處理的View繪制事件、待處理的post到Choreographer中事件煞躬,Android系統(tǒng)每隔16.7ms發(fā)出VSYNC信號(hào)线婚,Choreographer.FrameDisplayEventReceiver收到信號(hào)后調(diào)用onVsync方法洋措,最終會(huì)調(diào)用Choreographer.doFrame()方法剑按,在doFrame方法中處理輸入事件、動(dòng)畫事件澜驮、View繪制陷揪、post到Choreographer中的FrameCallback;我們可以使用Choreographer#postFrameCallback設(shè)置callback與Choreographer交互杂穷,設(shè)置的FrameCallCack(doFrame方法)會(huì)在下一個(gè)frame被渲染時(shí)觸發(fā)(即下一個(gè)VSYNC到來時(shí)執(zhí)行)悍缠;Choreographer更多內(nèi)容請(qǐng)參考Android Choreographer 源碼分析
Android動(dòng)畫原理簡單描述:將View的一次大的屬性變化拆分為多次小的屬性變化,在每次VSYNC信號(hào)到來時(shí)耐量,根據(jù)當(dāng)前時(shí)間和插值器來計(jì)算當(dāng)前View屬性的值飞蚓,然后給View設(shè)置該屬性值,直到動(dòng)畫執(zhí)行完畢廊蜒。其中Choreographer將動(dòng)畫拆分成一次次小的屬性變化趴拧,Choreographer是動(dòng)畫的指揮者。理想情況下山叮,屬性刷新次數(shù)(動(dòng)畫拆分為多次小的屬性變化) = 動(dòng)畫執(zhí)行時(shí)間/16.7ms 著榴。