7.5 屬性動(dòng)畫(huà)

7.3.4 對(duì)任意屬性做動(dòng)畫(huà)

這里先提出一個(gè)問(wèn)題:給Button加一個(gè)動(dòng)畫(huà)与帆,讓這個(gè)Button的寬度從當(dāng)前寬度增加到500px了赌。也許你會(huì)說(shuō),這很簡(jiǎn)單玄糟,用View動(dòng)畫(huà)就可以搞定勿她。很快你就會(huì)恍然大悟,原來(lái)View動(dòng)畫(huà)根本不支持對(duì)寬度進(jìn)行動(dòng)畫(huà)茶凳。沒(méi)錯(cuò)嫂拴,View動(dòng)畫(huà)只支持四種類型:平移,旋轉(zhuǎn)贮喧,縮放筒狠,不透明度。當(dāng)然用X方向縮放(scaleX)可以讓ButtonX方向放大箱沦,看起來(lái)好像是寬度增加了辩恼,實(shí)際上不是,只是Button被放大了而已,而且由于只X方向被放大灶伊,這個(gè)時(shí)候Button的背景以及上面的文本都被拉伸了疆前,甚至有可能Button會(huì)超出屏幕。

@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.btn:
            ObjectAnimator.ofInt(button,"width",500).setDuration(2000).start();
            break;
    }
}

上述代碼運(yùn)行后發(fā)現(xiàn)沒(méi)效果聘萨,其實(shí)沒(méi)效果是對(duì)的竹椒,如果隨便傳遞一個(gè)屬性過(guò)去,輕則沒(méi)動(dòng)畫(huà)效果米辐,重則程序直接Crash胸完。

屬性動(dòng)畫(huà)的原理:屬性動(dòng)畫(huà)要求動(dòng)畫(huà)作用的對(duì)象提供該屬性的getset方法,屬性動(dòng)畫(huà)根據(jù)外界傳遞的該屬性的初始值和最終值翘贮,以動(dòng)畫(huà)的效果多次去調(diào)用set方法赊窥,每次傳遞給set方法的值都不一樣,確切來(lái)說(shuō)狸页,隨著時(shí)間的推移锨能,所傳遞的值越來(lái)越接近最終值。總結(jié)一下芍耘,我們對(duì)object的屬性abc做動(dòng)畫(huà)址遇,如果想讓動(dòng)畫(huà)生效,要同時(shí)滿足兩個(gè)條件齿穗。

  • object必須要提供setAbc方法傲隶,如果動(dòng)畫(huà)的時(shí)候沒(méi)有傳遞初始值,那么還要提供getAbc方法窃页,因?yàn)橄到y(tǒng)要去取abc屬性的初始值(如果這條不滿足,程序直接Crash)复濒。

  • objectsetAbc對(duì)屬性abc所做的改變必須能夠通過(guò)某種方法反應(yīng)出來(lái)脖卖,比如會(huì)帶來(lái)UI的改變之類的(如果這條不滿足,動(dòng)畫(huà)無(wú)效果但不會(huì)Crash)巧颈。

以上條件缺一不可畦木,Button內(nèi)部雖然提供了getWidthsetWidth方法,但是這個(gè)setWidth方法并不是改變視圖的大小砸泛,它是TextView新添加的方法十籍,View是沒(méi)有這個(gè)setWidth方法的,由于Button繼承了TextView唇礁,所以Button也就有了setWidth方法勾栗。

打開(kāi)TextView的源碼,可以發(fā)現(xiàn)getWidth的確是獲取View的寬度的盏筐,但是setWidth是設(shè)置TextView的最大寬度和最小寬度的围俘,這個(gè)和TextView的寬度不是一個(gè)東西。具體來(lái)說(shuō),TextView的寬度對(duì)應(yīng)XML中的android:layout_width屬性界牡,而TextView還有一個(gè)屬性android:width簿寂,這個(gè)android:width屬性就對(duì)應(yīng)了TextViewsetWidth方法∷尥觯總之常遂,TextViewButtonsetWidthgetWidth干的不是同一件事情挽荠,通過(guò)setWidth無(wú)法改變控件的寬度克胳,所以對(duì)width做屬性動(dòng)畫(huà)沒(méi)有效果。對(duì)應(yīng)于屬性動(dòng)畫(huà)的兩個(gè)條件來(lái)說(shuō)坤按,本例中動(dòng)畫(huà)不生效的原因是只滿足了條件1而未滿足條件2毯欣。

針對(duì)上述問(wèn)題,官方文檔上告訴我們有3種解決方法:

  • 給你的對(duì)象加上getset方法臭脓,如果你有權(quán)限的話酗钞。
  • 用一個(gè)類來(lái)包裝原始對(duì)象,間接為其提供getset方法来累。
@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.btn:
            ViewWrapper wrapper = new ViewWrapper(button);
            ObjectAnimator.ofInt(wrapper,"width",500).setDuration(2000).start();
            break;
    }
}

private static class ViewWrapper {

    private View mTarget;

    public ViewWrapper(View mTarget) {
        this.mTarget = mTarget;
    }

    public int getWidth() {
        return mTarget.getLayoutParams().width;
    }

    public void setWidth(int width) {
        mTarget.getLayoutParams().width = width;
        mTarget.requestLayout();
    }
}

提供了ViewWrapper 類專門(mén)用于包裝View砚作,然后我們對(duì)ViewWrapperwidth屬性做動(dòng)畫(huà),并且在setWidth方法中修改其內(nèi)部的target的寬度嘹锁,而target實(shí)際上就是我們包裝的Button葫录。

  • 采用ValueAnimator,監(jiān)聽(tīng)動(dòng)畫(huà)過(guò)程领猾,自己實(shí)現(xiàn)屬性的改變米同。
    ValueAnimator本身不作用于任何對(duì)象,也就是說(shuō)直接使用它沒(méi)有任何動(dòng)畫(huà)效果摔竿。它可以對(duì)一個(gè)值做動(dòng)畫(huà)面粮,然后我們可以監(jiān)聽(tīng)其動(dòng)畫(huà)過(guò)程。在動(dòng)畫(huà)過(guò)程中修改我們的對(duì)象的屬性值继低,這樣也就相當(dāng)于我們的對(duì)象做了動(dòng)畫(huà)熬苍。
@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.btn:
            performAnimate(button,button.getWidth(),500);
            break;
    }
}

private void performAnimate(final View target,final int start,final int end) {
    ValueAnimator valueAnimator = ValueAnimator.ofInt(1,100);
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

        // 持有一個(gè)IntEvaluator對(duì)象,方便下面估值的時(shí)候使用
        private IntEvaluator mEvaluator = new IntEvaluator();

        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            
            // 獲得當(dāng)前動(dòng)畫(huà)的進(jìn)度值袁翁,整型柴底,1~100之間
            int currentValue = (int) animation.getAnimatedValue();
            
            // 獲得當(dāng)前進(jìn)度占整個(gè)動(dòng)畫(huà)過(guò)程的比例,浮點(diǎn)型 0~1之間
            float fraction = animation.getAnimatedFraction();
            
            // 直接調(diào)用整型估值器粱胜,通過(guò)比例計(jì)算出寬度柄驻,然后在設(shè)給Button
            target.getLayoutParams().width = mEvaluator.evaluate(fraction,start,end);
            target.requestLayout();
        }
    });
    valueAnimator.setDuration(5000).start();
}

它會(huì)在5000ms內(nèi)將一個(gè)數(shù)從1變到100,然后動(dòng)畫(huà)的每一幀會(huì)回調(diào)onAnimationUpdate方法年柠。在這個(gè)方法里凿歼,我們可以獲取當(dāng)前的值(1~100)和當(dāng)前值所占的比例褪迟,我們可以計(jì)算出Button現(xiàn)在的寬度應(yīng)該是多少。比如時(shí)間過(guò)了一半答憔,當(dāng)前值是50味赃,比例為0.5,假設(shè)Button的起始寬度是100px虐拓,最終寬度是500px心俗,那么Button應(yīng)該增加的寬度是400 * 0.5 = 200,那么當(dāng)前Button的寬度應(yīng)該為初始寬度 + 增加寬度(100 + 200 = 300)蓉驹。

7.3.5 屬性動(dòng)畫(huà)的工作原理

屬性動(dòng)畫(huà)要求動(dòng)畫(huà)作用的對(duì)象提供該屬性的set方法城榛,屬性動(dòng)畫(huà)根據(jù)你傳遞的該屬性的初始值和最終值,以動(dòng)畫(huà)的效果多次去調(diào)用set方法态兴。每次傳遞給set方法的值都不一樣狠持,確切來(lái)說(shuō)是隨著時(shí)間的推移,所傳遞的值越來(lái)越接近最終值瞻润。如果動(dòng)畫(huà)的時(shí)候沒(méi)有傳遞初始值喘垂,那么還要提供get方法,因?yàn)橄到y(tǒng)要去獲取屬性的初始值绍撞。對(duì)于屬性動(dòng)畫(huà)來(lái)說(shuō)正勒,其動(dòng)畫(huà)過(guò)程中所做的就是這么多。

7.4 使用動(dòng)畫(huà)的注意事項(xiàng)

通過(guò)動(dòng)畫(huà)可以實(shí)現(xiàn)一些比較絢麗的效果傻铣,但是在使用過(guò)程中章贞,也需要注意一些事情,主要分為下面幾類:

1. OOM問(wèn)題

這個(gè)問(wèn)題主要出現(xiàn)在幀動(dòng)畫(huà)中非洲,當(dāng)圖片數(shù)量較多且圖片較大時(shí)就極易出現(xiàn)OOM鸭限,這個(gè)在實(shí)際的開(kāi)發(fā)中要尤其注意,盡量避免使用幀動(dòng)畫(huà)两踏。

2. 內(nèi)存泄漏

在屬性動(dòng)畫(huà)中有一類無(wú)限循環(huán)的動(dòng)畫(huà)里覆,這類動(dòng)畫(huà)需要在Activity退出時(shí)及時(shí)停止,否則將導(dǎo)致Activity無(wú)法釋放從而造成內(nèi)存泄漏缆瓣,通過(guò)驗(yàn)證后發(fā)現(xiàn)View動(dòng)畫(huà)并不存在此問(wèn)題景醇。

3. 兼容性問(wèn)題

動(dòng)畫(huà)在3.0以下的系統(tǒng)上有兼容性問(wèn)題瑟俭,在某些特殊場(chǎng)景可能無(wú)法正常工作躺同,因此要做好適配工作进苍。

4. View動(dòng)畫(huà)的問(wèn)題

View動(dòng)畫(huà)是對(duì)View的影像做動(dòng)畫(huà)赔桌,并不是真正地改變View的狀態(tài)甘耿,因此有時(shí)候會(huì)出現(xiàn)動(dòng)畫(huà)完成后View無(wú)法隱藏的現(xiàn)象砾赔,即setVisibility(View.GONE)失效了旦事,這個(gè)時(shí)候只要調(diào)用view.clearAnimation()清除View動(dòng)畫(huà)即可解決此問(wèn)題忧便。

5. 不要使用px

在進(jìn)行動(dòng)畫(huà)的過(guò)程中族吻,要盡量使用dp,使用px會(huì)導(dǎo)致在不同的設(shè)備上有不同的效果。

6. 動(dòng)畫(huà)元素的交互

View移動(dòng)(平移)后超歌,在Android3.0以前的系統(tǒng)上砍艾,不管是View動(dòng)畫(huà)還是屬性動(dòng)畫(huà),新位置均無(wú)法觸發(fā)單擊事件巍举,同時(shí)脆荷,老位置仍然可以觸發(fā)單擊事件。盡管View已經(jīng)在視覺(jué)上不存在了懊悯,將View移回原位置以后蜓谋,原位置的單擊事件繼續(xù)生效。從3.0開(kāi)始炭分,屬性動(dòng)畫(huà)的單擊事件觸發(fā)位置為移動(dòng)后的位置桃焕,但是View動(dòng)畫(huà)仍然在原位置。

7. 硬件加速

使用動(dòng)畫(huà)的過(guò)程中捧毛,建議開(kāi)啟硬件加速观堂,這樣會(huì)提高動(dòng)畫(huà)的流暢性。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末岖妄,一起剝皮案震驚了整個(gè)濱河市型将,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌荐虐,老刑警劉巖七兜,帶你破解...
    沈念sama閱讀 222,183評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異福扬,居然都是意外死亡腕铸,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)铛碑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)狠裹,“玉大人,你說(shuō)我怎么就攤上這事汽烦√尾ぃ” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,766評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵撇吞,是天一觀的道長(zhǎng)俗冻。 經(jīng)常有香客問(wèn)我,道長(zhǎng)牍颈,這世上最難降的妖魔是什么迄薄? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,854評(píng)論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮煮岁,結(jié)果婚禮上讥蔽,老公的妹妹穿的比我還像新娘涣易。我一直安慰自己,他們只是感情好冶伞,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布新症。 她就那樣靜靜地躺著,像睡著了一般碰缔。 火紅的嫁衣襯著肌膚如雪账劲。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,457評(píng)論 1 311
  • 那天金抡,我揣著相機(jī)與錄音瀑焦,去河邊找鬼。 笑死梗肝,一個(gè)胖子當(dāng)著我的面吹牛榛瓮,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播巫击,決...
    沈念sama閱讀 40,999評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼禀晓,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了坝锰?” 一聲冷哼從身側(cè)響起粹懒,我...
    開(kāi)封第一講書(shū)人閱讀 39,914評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎顷级,沒(méi)想到半個(gè)月后凫乖,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,465評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡弓颈,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評(píng)論 3 342
  • 正文 我和宋清朗相戀三年帽芽,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片翔冀。...
    茶點(diǎn)故事閱讀 40,675評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡导街,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出纤子,到底是詐尸還是另有隱情搬瑰,我是刑警寧澤,帶...
    沈念sama閱讀 36,354評(píng)論 5 351
  • 正文 年R本政府宣布控硼,位于F島的核電站跌捆,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏象颖。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評(píng)論 3 335
  • 文/蒙蒙 一姆钉、第九天 我趴在偏房一處隱蔽的房頂上張望说订。 院中可真熱鬧抄瓦,春花似錦、人聲如沸陶冷。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,514評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)埂伦。三九已至煞额,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間沾谜,已是汗流浹背膊毁。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,616評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留基跑,地道東北人婚温。 一個(gè)月前我還...
    沈念sama閱讀 49,091評(píng)論 3 378
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像媳否,于是被迫代替她去往敵國(guó)和親栅螟。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評(píng)論 2 360

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