View動(dòng)畫(huà)執(zhí)行過(guò)程和插值器作用

示例

博客
補(bǔ)間動(dòng)畫(huà)的使用很簡(jiǎn)單,如下面代碼,讓圖片旋轉(zhuǎn)360度:

        animation = new RotateAnimation(0,360);
        animation.setDuration(3000);
        iv.startAnimation(animation);

那么補(bǔ)間動(dòng)畫(huà)說(shuō)怎么執(zhí)行的,插值器又是怎么用上的能?

動(dòng)畫(huà)的啟動(dòng) View

從動(dòng)畫(huà)啟動(dòng)開(kāi)始吧,看View的startAnimation方法:

/frameworks/base/core/java/android/view/View.java:

    public void startAnimation(Animation animation) {
        animation.setStartTime(Animation.START_ON_FIRST_FRAME);
        setAnimation(animation);
        invalidateParentCaches();
        invalidate(true);
    }
    public void setAnimation(Animation animation) {
        mCurrentAnimation = animation;
        if (animation != null) {
            ......
        }
    }

這里面沒(méi)幾行代碼,首先把動(dòng)畫(huà)設(shè)置給內(nèi)部的一個(gè)變量,然后調(diào)用invalidate(true)方法。

這個(gè)方法會(huì)引起View的draw()方法的執(zhí)行,并且是整個(gè)View的重繪。

/frameworks/base/core/java/android/view/View.java:

public Animation getAnimation() {
        return mCurrentAnimation;
    }
boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
        Transformation transformToApply = null;
        boolean concatMatrix = false;
        //拿到動(dòng)畫(huà)
        final Animation a = getAnimation();
        //動(dòng)畫(huà)不為空,說(shuō)明有動(dòng)畫(huà)要執(zhí)行
        if (a != null) {
            more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired);
            concatMatrix = a.willChangeTransformationMatrix();
            if (concatMatrix) {
                mPrivateFlags3 |= PFLAG3_VIEW_IS_ANIMATING_TRANSFORM;
            }
            //獲取Transformation,里面包換透明度和矩陣,這個(gè)Transformation的值在上面已經(jīng)設(shè)置好了
            transformToApply = parent.getChildTransformation();
        } else {
        }
        //根據(jù)Transformation進(jìn)行繪制。
        return more;
    }

調(diào)用本類的applyLegacyAnimation方法。

/frameworks/base/core/java/android/view/View.java:

private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime,
            Animation a, boolean scalingRequired) {
        Transformation invalidationTransform;
        final int flags = parent.mGroupFlags;
        final boolean initialized = a.isInitialized();
        if (!initialized) {
            //初始化動(dòng)畫(huà)
            a.initialize(mRight - mLeft, mBottom - mTop, parent.getWidth(), parent.getHeight());
            a.initializeInvalidateRegion(0, 0, mRight - mLeft, mBottom - mTop);
            if (mAttachInfo != null) a.setListenerHandler(mAttachInfo.mHandler);
            onAnimationStart();
        }
        //注意這里也是通過(guò)這個(gè)方法拿到一個(gè)Transformation。
        final Transformation t = parent.getChildTransformation();
        //獲取動(dòng)畫(huà)的變化值,并返回是否還有下一幀。
        boolean more = a.getTransformation(drawingTime, t, 1f);
        if (scalingRequired && mAttachInfo.mApplicationScale != 1f) {
            if (parent.mInvalidationTransformation == null) {
                parent.mInvalidationTransformation = new Transformation();
            }
            invalidationTransform = parent.mInvalidationTransformation;
            a.getTransformation(drawingTime, invalidationTransform, 1f);
        } else {
            invalidationTransform = t;
        }
        if (more) {
            //如果有下一幀,就繼續(xù)刷新繪制
        }
        return more;
    }

動(dòng)畫(huà)的動(dòng)畫(huà)值計(jì)算設(shè)置

/frameworks/base/core/java/android/view/animation/Animation.java:

public boolean getTransformation(long currentTime, Transformation outTransformation) {
        if (mStartTime == -1) {
            mStartTime = currentTime;
        }
        //轉(zhuǎn)化為標(biāo)準(zhǔn)時(shí)間
        final long startOffset = getStartOffset();
        final long duration = mDuration;
        float normalizedTime;
        if (duration != 0) {
            normalizedTime = ((float) (currentTime - (mStartTime + startOffset))) /
                    (float) duration;
        }
        if ((normalizedTime >= 0.0f || mFillBefore) && (normalizedTime <= 1.0f || mFillAfter)) {
        ......
        //通過(guò)標(biāo)準(zhǔn)時(shí)間,用插值器計(jì)算插值器轉(zhuǎn)換之后的值
            final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime);
            //調(diào)用子類實(shí)現(xiàn)的方法,
            applyTransformation(interpolatedTime, outTransformation);
        }
        return mMore;
    }
protected void applyTransformation(float interpolatedTime, Transformation t) {
}

首先計(jì)算標(biāo)準(zhǔn)時(shí)間。標(biāo)準(zhǔn)時(shí)間是0到1的值,表示時(shí)間的進(jìn)度。通過(guò)這個(gè)進(jìn)度計(jì)算動(dòng)畫(huà)的進(jìn)度。計(jì)算方法是,先用開(kāi)始時(shí)間和延遲開(kāi)始時(shí)間計(jì)算動(dòng)畫(huà)真正的開(kāi)始時(shí)間,然后用當(dāng)前時(shí)間減去動(dòng)畫(huà)真正開(kāi)始的時(shí)間,算出動(dòng)畫(huà)已經(jīng)運(yùn)行的時(shí)間。用這個(gè)時(shí)間除以動(dòng)畫(huà)的總運(yùn)行時(shí)間久得到當(dāng)前動(dòng)畫(huà)的進(jìn)度。

插值器

插值器改變的就是改變不同時(shí)間進(jìn)度上的值,時(shí)間的流逝是線性的,速度是不變的,但是插值器通過(guò)改變不同時(shí)間上動(dòng)畫(huà)的值,達(dá)到控制動(dòng)畫(huà)的目的。

默認(rèn)是加速加速插值器,里面是一個(gè)余弦曲線,隨著標(biāo)準(zhǔn)時(shí)間從0到1,返回的數(shù)值是先加速再減速的,動(dòng)畫(huà)就會(huì)先變快在變慢,第一個(gè)效果圖中看的很明顯。

/frameworks/base/core/java/android/view/animation/AccelerateDecelerateInterpolator.java:

public float getInterpolation(float input) {
        return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
    }

下面可以看一下線性插值器,他就原原本本的返回了標(biāo)準(zhǔn)時(shí)間,不做任何改變,所以動(dòng)畫(huà)就會(huì)勻速執(zhí)行:

/frameworks/base/core/java/android/view/animation/LinearInterpolator.java

    public float getInterpolation(float input) {
        return input;
    }

Animation的子類實(shí)現(xiàn)applyTransformation方法

Animation的applyTransformation方法是一個(gè)空方法,需要子類去實(shí)現(xiàn)。下面看一啊AlphaAnimation的實(shí)現(xiàn),現(xiàn)獲取透明度總共要變化的值,然后通過(guò)傳進(jìn)來(lái)的插值器計(jì)算出的進(jìn)度值,算出這個(gè)時(shí)間點(diǎn)上透明度應(yīng)該是多少,然后設(shè)置給Transformation:

/Users/sunlinlin/Documents/AndroidSourcePart/frameworks/base/core/java/android/view/animation/AlphaAnimation.java

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        final float alpha = mFromAlpha;
        t.setAlpha(alpha + ((mToAlpha - alpha) * interpolatedTime));
    }

AlphaAnimation里給傳進(jìn)來(lái)的Transformation設(shè)置了alpha值。Transformation主要有兩個(gè)量,一個(gè)透明度,一個(gè)是矩陣。繪制時(shí)根據(jù)這個(gè)類里面存儲(chǔ)的量來(lái)繪制,達(dá)到動(dòng)畫(huà)的效果。

例如旋轉(zhuǎn)動(dòng)畫(huà)RotateAnimation,改變的就是矩陣,先算出動(dòng)畫(huà)一共要旋轉(zhuǎn)的角度,然后根據(jù)插值器計(jì)算的進(jìn)度值算出當(dāng)前時(shí)間點(diǎn)上應(yīng)該旋轉(zhuǎn)到什么角度,然后設(shè)置給Transformation。

/frameworks/base/core/java/android/view/animation/RotateAnimation.java

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        float degrees = mFromDegrees + ((mToDegrees - mFromDegrees) * interpolatedTime);
        float scale = getScaleFactor();
        if (mPivotX == 0.0f && mPivotY == 0.0f) {
            t.getMatrix().setRotate(degrees);
        } else {
            t.getMatrix().setRotate(degrees, mPivotX * scale, mPivotY * scale);
        }
    }

這時(shí),回到上面View的draw()方法里,就會(huì)根據(jù)后面對(duì)Transformation的設(shè)置進(jìn)行畫(huà)面的繪制,一幀一幀的繪制就成了動(dòng)畫(huà)。

這也能解釋為什么補(bǔ)間動(dòng)畫(huà)不會(huì)改變控件的真正位置了,因?yàn)檫@個(gè)動(dòng)畫(huà)只是重新對(duì)空間進(jìn)行了draw,改變的只是看起來(lái)的樣子,所以點(diǎn)擊事件還得點(diǎn)擊原來(lái)的地方。

簡(jiǎn)單的自定義插值器

插值器前面說(shuō)的作用就是,在決定不同時(shí)間進(jìn)度上的動(dòng)畫(huà)進(jìn)度。時(shí)間進(jìn)度是從0到1,而動(dòng)畫(huà)進(jìn)度不一定非要從0到1.

比如,就已開(kāi)始設(shè)置那個(gè)動(dòng)畫(huà),3秒時(shí)間從0度旋轉(zhuǎn)到360度,那么正常的他的動(dòng)畫(huà)進(jìn)度就是:時(shí)間從0到3秒,角度從0到360.

動(dòng)畫(huà)的進(jìn)度是可以再插值器中隨便設(shè)置的,大于1也沒(méi)可以。

下面是例子

自定義一個(gè)插值器

public class MyInterpolator implements Interpolator {
    @Override
    public float getInterpolation(float input) {
        return 2*input;
    }
}

傳進(jìn)來(lái)的標(biāo)準(zhǔn)時(shí)間是0到1 ,返回的動(dòng)畫(huà)進(jìn)度從0到2. 寫(xiě)的是轉(zhuǎn)到360度,但是動(dòng)畫(huà)會(huì)從0轉(zhuǎn)到720度,轉(zhuǎn)兩圈,速度是勻速。

        animation = new RotateAnimation(0,360);
        animation.setDuration(3000);
        animation.setInterpolator(new MyInterpolator());
        iv.startAnimation(animation);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容