Android Loading動(dòng)畫分析設(shè)計(jì)

android6.0上有了很炫酷的開機(jī)動(dòng)畫袖扛,雖不知其實(shí)現(xiàn)原理是什么,但感覺扎心了J攻锰!有時(shí)間一定去翻一下源碼,本著對(duì)loading動(dòng)畫的熱愛妓雾,后來找到了LoadingDrawable庫娶吞,還是很炫酷的,簡(jiǎn)要分析:

loadingdrawable.gif

原理

android中的動(dòng)畫最后都是實(shí)現(xiàn)canvas上繪制械姻,這些動(dòng)畫也不例外妒蛇,不得不說作者真是運(yùn)用DrawableValueAnimator楷拳,Canvas到了極致绣夺。庫中有很多個(gè)實(shí)現(xiàn),下面選scenery中的DayNightLoading動(dòng)畫分析其實(shí)現(xiàn)過程欢揖。

  • 整體設(shè)計(jì)流程

LoadingView是最終在layout文件中的自定義view陶耍,繼承與ImageView,使用如下:

    <app.dinus.com.loadingdrawable.LoadingView
        android:id="@+id/day_night_view"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:background="#ff071c28"
        app:loading_renderer="DayNightLoadingRenderer" />

發(fā)現(xiàn)自定義屬性DayNightLoadingRenderer(懷疑作者多寫個(gè)er >..<)她混,通過這里傳入的參數(shù)烈钞,在構(gòu)造方法中使用工廠方法LoadingRendererFactory.createLoadingRenderer(context, loadingRendererId)構(gòu)造相應(yīng)的LoadingRenderer泊碑,它就是主角,通過setLoadingRenderer()創(chuàng)建LoadingDrawable毯欣,LoadingDrawable繼承于Drawable馒过,最后調(diào)用setImageDrawable顯示。
剝洋蔥一樣一層一層分析酗钞,LoadingView就是基本自定義view的流程腹忽,進(jìn)入LoadingDrawable發(fā)現(xiàn):

private final Callback mCallback = new Callback() {
        @Override
        public void invalidateDrawable(Drawable d) {
            invalidateSelf();
        }

        @Override
        public void scheduleDrawable(Drawable d, Runnable what, long when) {
            scheduleSelf(what, when);
        }

        @Override
        public void unscheduleDrawable(Drawable d, Runnable what) {
            unscheduleSelf(what);
        }
    };

Android中的Callback太多了,我承認(rèn)自己很low這個(gè)沒見過...砚作,啪啪啪(鼠標(biāo)聲)點(diǎn)進(jìn)源碼看看這是什么鬼窘奏,是android.graphics.drawable.Drawable中的靜態(tài)接口,注釋寫的很明白如果想做一個(gè)動(dòng)畫的drawable葫录,這個(gè)drawable又繼承于{@link android.graphics.drawable.Drawable Drawable}着裹,那么就實(shí)現(xiàn)這個(gè)接口就好了,自定義的drawable通過setCallback后能schedule并execute動(dòng)畫的變化压昼,那就很明確了求冷,這就是個(gè)動(dòng)畫Drawable用來不斷繪制自己的接口瘤运,自定義Drawable需要set窍霞。LoadingDrawable中為了完成動(dòng)畫的各個(gè)狀態(tài)變化,直接實(shí)現(xiàn)了Animatable接口拯坟。
接下來看LoadingRenderer類但金,是個(gè)抽象類,那肯定就是為了后續(xù)拓展各種Renderer而設(shè)計(jì)成抽象類郁季。類中定義了缺省的大小和動(dòng)畫時(shí)間冷溃,如何實(shí)現(xiàn)動(dòng)畫的插值器呢,這里使用了ValueAnimator梦裂,是屬性動(dòng)畫的一種似枕,其缺省插值器是AccelerateDecelerateInterpolator,通過mRenderAnimator.addUpdateListener更新動(dòng)畫的當(dāng)前值年柠,并重繪凿歼,具體為監(jiān)聽過程調(diào)用computeRender((float) animation.getAnimatedValue());invalidateSelf();
這里順帶提一下LoadingRendererFactory冗恨,工廠類答憔,工廠類采用SparseArray存放id與對(duì)應(yīng)的類,通過反射獲取相應(yīng)的類構(gòu)造函數(shù)掀抹,從而獲取相應(yīng)的對(duì)象虐拓。
到了關(guān)鍵人物DayNightLoadingRenderer,繼承抽象類LoadingRenderer傲武。

  • 分析DayNightLoadingRenderer

mInitSun$MoonCoordinateY關(guān)鍵變量1蓉驹,太陽和月亮升起的起始位置城榛。
mMaxSun$MoonRiseDistance關(guān)鍵變量2,上升的最大距離戒幔。
那么問題來了吠谢,drawable是如何知道什么時(shí)候繪制什么曲線的呢,draw中給出答案:

        if (mSunCoordinateY < mInitSun$MoonCoordinateY) {
            canvas.drawCircle(arcBounds.centerX(), 
            mSunCoordinateY, mSun$MoonRadius, mPaint);
        }

        if (mMoonCoordinateY < mInitSun$MoonCoordinateY) {
            int moonSaveCount = canvas.save();
            canvas.rotate(mMoonRotation, arcBounds.centerX(), mMoonCoordinateY);
            canvas.drawPath(createMoonPath(arcBounds.centerX(), mMoonCoordinateY), mPaint);
            canvas.restoreToCount(moonSaveCount);
        }

是按照太陽和月亮的當(dāng)前高度與初始位置高度 的 相對(duì)位置判斷如何繪制圖形诗茎。具體canvas的知識(shí)這里就不詳細(xì)介紹了工坊,網(wǎng)上很多。
還記得剛才computeRender((float) animation.getAnimatedValue())invalidateSelf()吧敢订,這里實(shí)現(xiàn)了computeRender:

if (renderProgress <= SUN_RISE_DURATION_OFFSET) {
            ...
}

if (renderProgress <= SUN_ROTATE_DURATION_OFFSET && renderProgress > SUN_RISE_DURATION_OFFSET) {
            ...

            ...
}
...

...

if (renderProgress <= MOON_DECREASE_END_DURATION_OFFSET && renderProgress > MOON_DECREASE_START_DURATION_OFFSET) {
           ...
}

這里清一色通過renderProgress來判斷當(dāng)前動(dòng)畫的進(jìn)度王污,當(dāng)前類中定義了動(dòng)畫的一些關(guān)鍵點(diǎn),比如:SUN_DECREASE_DURATION_OFFSET楚午、STAR_RISE_START_DURATION_OFFSET等昭齐,這些代表太陽落下、星星升起等等矾柜。通過關(guān)鍵點(diǎn)的判斷改變太陽阱驾、月亮、星星的一些屬性及太陽怪蔑、月亮的y軸位置里覆。最后不斷重新計(jì)算render,不斷invalidateSelf缆瓣,實(shí)現(xiàn)整個(gè)動(dòng)畫喧枷。

總結(jié)

熟悉drawable、valueAnimator弓坞、callback是基礎(chǔ)隧甚,但是實(shí)現(xiàn)動(dòng)畫的具體變換計(jì)算、如何繪制才是重點(diǎn)渡冻,這得一點(diǎn)點(diǎn)調(diào)出來戚扳,實(shí)在佩服。這兩天看看計(jì)算過程族吻,容易講的話帽借,再寫一篇。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末呼奢,一起剝皮案震驚了整個(gè)濱河市宜雀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌握础,老刑警劉巖辐董,帶你破解...
    沈念sama閱讀 217,185評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異禀综,居然都是意外死亡简烘,警方通過查閱死者的電腦和手機(jī)苔严,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來孤澎,“玉大人届氢,你說我怎么就攤上這事「残瘢” “怎么了退子?”我有些...
    開封第一講書人閱讀 163,524評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)型将。 經(jīng)常有香客問我寂祥,道長(zhǎng),這世上最難降的妖魔是什么七兜? 我笑而不...
    開封第一講書人閱讀 58,339評(píng)論 1 293
  • 正文 為了忘掉前任丸凭,我火速辦了婚禮,結(jié)果婚禮上腕铸,老公的妹妹穿的比我還像新娘惜犀。我一直安慰自己,他們只是感情好狠裹,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評(píng)論 6 391
  • 文/花漫 我一把揭開白布虽界。 她就那樣靜靜地躺著,像睡著了一般酪耳。 火紅的嫁衣襯著肌膚如雪浓恳。 梳的紋絲不亂的頭發(fā)上刹缝,一...
    開封第一講書人閱讀 51,287評(píng)論 1 301
  • 那天碗暗,我揣著相機(jī)與錄音,去河邊找鬼梢夯。 笑死言疗,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的颂砸。 我是一名探鬼主播噪奄,決...
    沈念sama閱讀 40,130評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼人乓!你這毒婦竟也來了勤篮?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,985評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤色罚,失蹤者是張志新(化名)和其女友劉穎碰缔,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體戳护,經(jīng)...
    沈念sama閱讀 45,420評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡金抡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評(píng)論 3 334
  • 正文 我和宋清朗相戀三年瀑焦,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片梗肝。...
    茶點(diǎn)故事閱讀 39,779評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡榛瓮,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出巫击,到底是詐尸還是另有隱情禀晓,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評(píng)論 5 345
  • 正文 年R本政府宣布坝锰,位于F島的核電站匆绣,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏什黑。R本人自食惡果不足惜崎淳,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望愕把。 院中可真熱鬧拣凹,春花似錦、人聲如沸恨豁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽橘蜜。三九已至菊匿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間计福,已是汗流浹背跌捆。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留象颖,地道東北人佩厚。 一個(gè)月前我還...
    沈念sama閱讀 47,876評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像说订,于是被迫代替她去往敵國(guó)和親抄瓦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容