Android屬性動(dòng)畫完全解析(下)没炒,Interpolator和ViewPropertyAnimator的用法

文章轉(zhuǎn)載至郭神的博客

大家好涛癌,歡迎繼續(xù)回到Android屬性動(dòng)畫完全解析。在上一篇文章當(dāng)中我們學(xué)習(xí)了屬性動(dòng)畫的一些進(jìn)階技巧窥浪,包括ValueAnimator和ObjectAnimator的高級(jí)用法祖很,那么除了這些之外,當(dāng)然還有一些其它的高級(jí)技巧在等著我們學(xué)習(xí)漾脂,因此本篇文章就對(duì)整個(gè)屬性動(dòng)畫完全解析系列收個(gè)尾假颇,來(lái)學(xué)習(xí)一下剩下的非常重要的高級(jí)技巧。

另外骨稿,本篇文章中使用的代碼是建立在上篇文章基礎(chǔ)之上的笨鸡,如果你還沒有閱讀過(guò)前面的文章,建議先去參考閱讀一下 Android屬性動(dòng)畫完全解析(中)坦冠,ValueAnimator和ObjectAnimator的高級(jí)用法 形耗。

Interpolator的用法

Interpolator這個(gè)東西很難進(jìn)行翻譯,直譯過(guò)來(lái)的話是補(bǔ)間器的意思辙浑,它的主要作用是可以控制動(dòng)畫的變化速率激涤,比如去實(shí)現(xiàn)一種非線性運(yùn)動(dòng)的動(dòng)畫效果。那么什么叫做非線性運(yùn)動(dòng)的動(dòng)畫效果呢判呕?就是說(shuō)動(dòng)畫改變的速率不是一成不變的倦踢,像加速運(yùn)動(dòng)以及減速運(yùn)動(dòng)都屬于非線性運(yùn)動(dòng)。

不過(guò)Interpolator并不是屬性動(dòng)畫中新增的技術(shù)侠草,實(shí)際上從Android 1.0版本開始就一直存在Interpolator接口了辱挥,而之前的補(bǔ)間動(dòng)畫當(dāng)然也是支持這個(gè)功能的。只不過(guò)在屬性動(dòng)畫中新增了一個(gè)TimeInterpolator接口边涕,這個(gè)接口是用于兼容之前的Interpolator的晤碘,這使得所有過(guò)去的Interpolator實(shí)現(xiàn)類都可以直接拿過(guò)來(lái)放到屬性動(dòng)畫當(dāng)中使用褂微,那么我們來(lái)看一下現(xiàn)在TimeInterpolator接口的所有實(shí)現(xiàn)類,如下圖所示:

可以看到园爷,TimeInterpolator接口已經(jīng)有非常多的實(shí)現(xiàn)類了宠蚂,這些都是Android系統(tǒng)內(nèi)置好的并且我們可以直接使用的Interpolator。每個(gè)Interpolator都有它各自的實(shí)現(xiàn)效果腮介,比如說(shuō)AccelerateInterpolator就是一個(gè)加速運(yùn)動(dòng)的Interpolator肥矢,而DecelerateInterpolator就是一個(gè)減速運(yùn)動(dòng)的Interpolator。

我覺得細(xì)心的朋友應(yīng)該早已經(jīng)發(fā)現(xiàn)了叠洗,在前面兩篇文章當(dāng)中我們所學(xué)到的所有屬性動(dòng)畫甘改,其實(shí)都不是在進(jìn)行一種線程運(yùn)動(dòng)。比如說(shuō)在“上”篇文章中使用ValueAnimator所打印的值如下所示:

可以看到灭抑,一開始的值變化速度明顯比較慢十艾,僅0.0開頭的就打印了4次,之后開始加速腾节,最后階段又開始減速忘嫉,因此我們可以很明顯地看出這一個(gè)先加速后減速的Interpolator。

那么再來(lái)看一下在“中”篇文章中完成的小球移動(dòng)加變色的功能案腺,如下圖所示:


從上圖中我們明顯可以看出庆冕,小球一開始運(yùn)動(dòng)速度比較慢,然后逐漸加速劈榨,中間的部分運(yùn)動(dòng)速度就比較快访递,接下來(lái)開始減速,最后緩緩?fù)W⊥薄A硗忸伾兓彩沁@種規(guī)律拷姿,一開始顏色變化的比較慢,中間顏色變化的很快旱函,最后階段顏色變化的又比較慢响巢。

從以上幾點(diǎn)我們就可以總結(jié)出一個(gè)結(jié)論了,使用屬性動(dòng)畫時(shí)棒妨,系統(tǒng)默認(rèn)的Interpolator其實(shí)就是一個(gè)先加速后減速的Interpolator踪古,對(duì)應(yīng)的實(shí)現(xiàn)類就是AccelerateDecelerateInterpolator。

當(dāng)然券腔,我們也可以很輕松地修改這一默認(rèn)屬性伏穆,將它替換成任意一個(gè)系統(tǒng)內(nèi)置好的Interpolator。就拿“中”篇文章中的代碼來(lái)舉例吧颅眶,MyAnimView中的startAnimation()方法是開啟動(dòng)畫效果的入口,這里我們對(duì)Point對(duì)象的坐標(biāo)稍做一下修改田弥,讓它變成一種垂直掉落的效果涛酗,代碼如下所示:

private void startAnimation() {  
    Point startPoint = new Point(getWidth() / 2, RADIUS);  
    Point endPoint = new Point(getWidth() / 2, getHeight() - RADIUS);  
    ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);  
    anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {  
        @Override  
        public void onAnimationUpdate(ValueAnimator animation) {  
            currentPoint = (Point) animation.getAnimatedValue();  
            invalidate();  
        }  
    });  
    anim.setDuration(2000);  
    anim.start();  
}  

這里主要是對(duì)Point構(gòu)造函數(shù)中的坐標(biāo)值進(jìn)行了一下改動(dòng),那么現(xiàn)在小球運(yùn)動(dòng)的動(dòng)畫效果應(yīng)該是從屏幕正中央的頂部掉落到底部。但是現(xiàn)在默認(rèn)情況下小球的下降速度肯定是先加速后減速的商叹,這不符合物理的常識(shí)規(guī)律燕刻,如果把小球視為一個(gè)自由落體的話,那么下降的速度應(yīng)該是越來(lái)越快的剖笙。我們?cè)鯓硬拍芨淖冞@一默認(rèn)行為呢卵洗?其實(shí)很簡(jiǎn)單,調(diào)用Animator的setInterpolator()方法就可以了弥咪,這個(gè)方法要求傳入一個(gè)實(shí)現(xiàn)TimeInterpolator接口的實(shí)例过蹂,那么比如說(shuō)我們想要實(shí)現(xiàn)小球下降越來(lái)越快的效果,就可以使用AccelerateInterpolator聚至,代碼如下所示:

private void startAnimation() {  
    Point startPoint = new Point(getWidth() / 2, RADIUS);  
    Point endPoint = new Point(getWidth() / 2, getHeight() - RADIUS);  
    ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);  
    anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {  
        @Override  
        public void onAnimationUpdate(ValueAnimator animation) {  
            currentPoint = (Point) animation.getAnimatedValue();  
            invalidate();  
        }  
    });  
    anim.setInterpolator(new AccelerateInterpolator(2f));  
    anim.setDuration(2500);  
    anim.start();  
}  

代碼很簡(jiǎn)單酷勺,這里調(diào)用了setInterpolator()方法,然后傳入了一個(gè)AccelerateInterpolator的實(shí)例扳躬,注意AccelerateInterpolator的構(gòu)建函數(shù)可以接收一個(gè)float類型的參數(shù)脆诉,這個(gè)參數(shù)是用于控制加速度的。現(xiàn)在運(yùn)行一下代碼贷币,效果如下圖所示:

OK击胜,效果非常明顯,說(shuō)明我們已經(jīng)成功替換掉了默認(rèn)的Interpolator役纹,AccelerateInterpolator確實(shí)是生效了偶摔。但是現(xiàn)在的動(dòng)畫效果看上去仍然是怪怪的妄呕,因?yàn)橐粋€(gè)小球從很高的地方掉落到地面上直接就靜止了崎页,這也是不符合物理規(guī)律的陡蝇,小球撞擊到地面之后應(yīng)該要反彈起來(lái)膛腐,然后再次落下陷猫,接著再反彈起來(lái)奠支,又再次落下抬探,以此反復(fù)组橄,最后靜止硫戈。這個(gè)功能我們當(dāng)然可以自己去寫锰什,只不過(guò)比較復(fù)雜,所幸的是丁逝,Android系統(tǒng)中已經(jīng)提供好了這樣一種Interpolator汁胆,我們只需要簡(jiǎn)單地替換一下就可以完成上面的描述的效果,代碼如下所示:

private void startAnimation() {  
    Point startPoint = new Point(getWidth() / 2, RADIUS);  
    Point endPoint = new Point(getWidth() / 2, getHeight() - RADIUS);  
    ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);  
    anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {  
        @Override  
        public void onAnimationUpdate(ValueAnimator animation) {  
            currentPoint = (Point) animation.getAnimatedValue();  
            invalidate();  
        }  
    });  
    anim.setInterpolator(new BounceInterpolator());  
    anim.setDuration(3000);  
    anim.start();  
}  

可以看到霜幼,我們只是將設(shè)置的Interpolator換成了BounceInterpolator的實(shí)例嫩码,而BounceInterpolator就是一種可以模擬物理規(guī)律,實(shí)現(xiàn)反復(fù)彈起效果的Interpolator罪既。另外還將整體的動(dòng)畫時(shí)間稍微延長(zhǎng)了一點(diǎn)铸题,因?yàn)樾∏蚍磸?fù)彈起需要比之前更長(zhǎng)的時(shí)間≌∷。現(xiàn)在重新運(yùn)行一下代碼,效果如下圖所示:

OK丢间!效果還是非常不錯(cuò)的探熔。那么這里我們只是選了幾個(gè)系統(tǒng)實(shí)現(xiàn)好的Interpolator,由于內(nèi)置Interpolator非常多烘挫,就不一一進(jìn)行講解了诀艰,大家可以自己去使用一下其它的幾種Interpolator來(lái)看一看效果。

但是饮六,只會(huì)用一下系統(tǒng)提供好的Interpolator其垄,我們顯然對(duì)自己的要求就太低了,既然是學(xué)習(xí)屬性動(dòng)畫的高級(jí)用法喜滨,那么自然要將它研究透了捉捅。下面我們就來(lái)看一下Interpolator的內(nèi)部實(shí)現(xiàn)機(jī)制是什么樣的,并且來(lái)嘗試寫一個(gè)自定義的Interpolator虽风。

首先看一下TimeInterpolator的接口定義棒口,代碼如下所示:

/** 
 * A time interpolator defines the rate of change of an animation. This allows animations 
 * to have non-linear motion, such as acceleration and deceleration. 
 */  
public interface TimeInterpolator {  
  
    /** 
     * Maps a value representing the elapsed fraction of an animation to a value that represents 
     * the interpolated fraction. This interpolated value is then multiplied by the change in 
     * value of an animation to derive the animated value at the current elapsed animation time. 
     * 
     * @param input A value between 0 and 1.0 indicating our current point 
     *        in the animation where 0 represents the start and 1.0 represents 
     *        the end 
     * @return The interpolation value. This value can be more than 1.0 for 
     *         interpolators which overshoot their targets, or less than 0 for 
     *         interpolators that undershoot their targets. 
     */  
    float getInterpolation(float input);  
}  

OK,接口還是非常簡(jiǎn)單的辜膝,只有一個(gè)getInterpolation()方法无牵。大家有興趣可以通過(guò)注釋來(lái)對(duì)這個(gè)接口進(jìn)行詳解的了解,這里我就簡(jiǎn)單解釋一下厂抖,getInterpolation()方法中接收一個(gè)input參數(shù)茎毁,這個(gè)參數(shù)的值會(huì)隨著動(dòng)畫的運(yùn)行而不斷變化,不過(guò)它的變化是非常有規(guī)律的忱辅,就是根據(jù)設(shè)定的動(dòng)畫時(shí)長(zhǎng)勻速增加七蜘,變化范圍是0到1。也就是說(shuō)當(dāng)動(dòng)畫一開始的時(shí)候input的值是0墙懂,到動(dòng)畫結(jié)束的時(shí)候input的值是1橡卤,而中間的值則是隨著動(dòng)畫運(yùn)行的時(shí)長(zhǎng)在0到1之間變化的。

說(shuō)到這個(gè)input的值损搬,我覺得有不少朋友可能會(huì)聯(lián)想到我們?cè)凇爸小逼恼轮惺褂眠^(guò)的fraction值碧库。那么這里的input和fraction有什么關(guān)系或者區(qū)別呢?答案很簡(jiǎn)單巧勤,input的值決定了fraction的值嵌灰。input的值是由系統(tǒng)經(jīng)過(guò)計(jì)算后傳入到getInterpolation()方法中的,然后我們可以自己實(shí)現(xiàn)getInterpolation()方法中的算法颅悉,根據(jù)input的值來(lái)計(jì)算出一個(gè)返回值沽瞭,而這個(gè)返回值就是fraction了。

因此剩瓶,最簡(jiǎn)單的情況就是input值和fraction值是相同的驹溃,這種情況由于input值是勻速增加的柒瓣,因而fraction的值也是勻速增加的,所以動(dòng)畫的運(yùn)動(dòng)情況也是勻速的吠架。系統(tǒng)中內(nèi)置的LinearInterpolator就是一種勻速運(yùn)動(dòng)的Interpolator,那么我們來(lái)看一下它的源碼是怎么實(shí)現(xiàn)的:

/** 
 * An interpolator where the rate of change is constant 
 */  
@HasNativeInterpolator  
public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {  
  
    public LinearInterpolator() {  
    }  
  
    public LinearInterpolator(Context context, AttributeSet attrs) {  
    }  
  
    public float getInterpolation(float input) {  
        return input;  
    }  
  
    /** @hide */  
    @Override  
    public long createNativeInterpolator() {  
        return NativeInterpolatorFactoryHelper.createLinearInterpolator();  
    }  
}  

這里我們只看getInterpolation()方法搂鲫,這個(gè)方法沒有任何邏輯傍药,就是把參數(shù)中傳遞的input值直接返回了,因此fraction的值就是等于input的值的魂仍,這就是勻速運(yùn)動(dòng)的Interpolator的實(shí)現(xiàn)方式拐辽。

當(dāng)然這是最簡(jiǎn)單的一種Interpolator的實(shí)現(xiàn)了,我們?cè)賮?lái)看一個(gè)稍微復(fù)雜一點(diǎn)的擦酌。既然現(xiàn)在大家都知道了系統(tǒng)在默認(rèn)情況下使用的是AccelerateDecelerateInterpolator俱诸,那我們就來(lái)看一下它的源碼吧,如下所示:

/** 
 * An interpolator where the rate of change starts and ends slowly but 
 * accelerates through the middle. 
 *  
 */  
@HasNativeInterpolator  
public class AccelerateDecelerateInterpolator implements Interpolator, NativeInterpolatorFactory {  
    public AccelerateDecelerateInterpolator() {  
    }  
      
    @SuppressWarnings({"UnusedDeclaration"})  
    public AccelerateDecelerateInterpolator(Context context, AttributeSet attrs) {  
    }  
      
    public float getInterpolation(float input) {  
        return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;  
    }  
  
    /** @hide */  
    @Override  
    public long createNativeInterpolator() {  
        return NativeInterpolatorFactoryHelper.createAccelerateDecelerateInterpolator();  
    }  
}  

代碼雖然沒有變長(zhǎng)很多赊舶,但是getInterpolation()方法中的邏輯已經(jīng)明顯變復(fù)雜了睁搭,不再是簡(jiǎn)單地將參數(shù)中的input進(jìn)行返回,而是進(jìn)行了一個(gè)較為復(fù)雜的數(shù)學(xué)運(yùn)算笼平。那這里我們來(lái)分析一下它的算法實(shí)現(xiàn)园骆,可以看到,算法中主要使用了余弦函數(shù)寓调,由于input的取值范圍是0到1锌唾,那么cos函數(shù)中的取值范圍就是π到2π。而cos(π)的結(jié)果是-1夺英,cos(2π)的結(jié)果是1晌涕,那么這個(gè)值再除以2加上0.5之后,getInterpolation()方法最終返回的結(jié)果值還是在0到1之間痛悯。只不過(guò)經(jīng)過(guò)了余弦運(yùn)算之后余黎,最終的結(jié)果不再是勻速增加的了,而是經(jīng)歷了一個(gè)先加速后減速的過(guò)程灸蟆。我們可以將這個(gè)算法的執(zhí)行情況通過(guò)曲線圖的方式繪制出來(lái)驯耻,結(jié)果如下圖所示:

可以看到,這是一個(gè)S型的曲線圖炒考,當(dāng)橫坐標(biāo)從0變化到0.2的時(shí)候可缚,縱坐標(biāo)的變化幅度很小,但是之后就開始明顯加速斋枢,最后橫坐標(biāo)從0.8變化到1的時(shí)候帘靡,縱坐標(biāo)的變化幅度又變得很小。

OK瓤帚,通過(guò)分析LinearInterpolator和AccelerateDecelerateInterpolator的源碼描姚,我們已經(jīng)對(duì)Interpolator的內(nèi)部實(shí)現(xiàn)機(jī)制有了比較清楚的認(rèn)識(shí)了涩赢,那么接下來(lái)我們就開始嘗試編寫一個(gè)自定義的Interpolator。

編寫自定義Interpolator最主要的難度都是在于數(shù)學(xué)計(jì)算方面的轩勘,由于我數(shù)學(xué)并不是很好筒扒,因此這里也就寫一個(gè)簡(jiǎn)單點(diǎn)的Interpolator來(lái)給大家演示一下。既然屬性動(dòng)畫默認(rèn)的Interpolator是先加速后減速的一種方式绊寻,這里我們就對(duì)它進(jìn)行一個(gè)簡(jiǎn)單的修改花墩,讓它變成先減速后加速的方式。新建DecelerateAccelerateInterpolator類澄步,讓它實(shí)現(xiàn)TimeInterpolator接口冰蘑,代碼如下所示:

public class DecelerateAccelerateInterpolator implements TimeInterpolator{  
  
    @Override  
    public float getInterpolation(float input) {  
        float result;  
        if (input <= 0.5) {  
            result = (float) (Math.sin(Math.PI * input)) / 2;  
        } else {  
            result = (float) (2 - Math.sin(Math.PI * input)) / 2;  
        }  
        return result;  
    }  
  
}  

這段代碼是使用正弦函數(shù)來(lái)實(shí)現(xiàn)先減速后加速的功能的,因?yàn)檎液瘮?shù)初始弧度的變化值非常大村缸,剛好和余弦函數(shù)是相反的祠肥,而隨著弧度的增加,正弦函數(shù)的變化值也會(huì)逐漸變小梯皿,這樣也就實(shí)現(xiàn)了減速的效果仇箱。當(dāng)弧度大于π/2之后,整個(gè)過(guò)程相反了過(guò)來(lái)东羹,現(xiàn)在正弦函數(shù)的弧度變化值非常小工碾,漸漸隨著弧度繼續(xù)增加,變化值越來(lái)越大百姓,弧度到π時(shí)結(jié)束渊额,這樣從0過(guò)度到π,也就實(shí)現(xiàn)了先減速后加速的效果垒拢。

同樣我們可以將這個(gè)算法的執(zhí)行情況通過(guò)曲線圖的方式繪制出來(lái)旬迹,結(jié)果如下圖所示:

可以看到,這也是一個(gè)S型的曲線圖求类,只不過(guò)曲線的方向和剛才是相反的奔垦。從上圖中我們可以很清楚地看出來(lái),一開始縱坐標(biāo)的變化幅度很大尸疆,然后逐漸變小椿猎,橫坐標(biāo)到0.5的時(shí)候縱坐標(biāo)變化幅度趨近于零,之后隨著橫坐標(biāo)繼續(xù)增加縱坐標(biāo)的變化幅度又開始變大寿弱,的確是先減速后加速的效果犯眠。

那么現(xiàn)在我們將DecelerateAccelerateInterpolator在代碼中進(jìn)行替換,如下所示:

private void startAnimation() {  
    Point startPoint = new Point(getWidth() / 2, RADIUS);  
    Point endPoint = new Point(getWidth() / 2, getHeight() - RADIUS);  
    ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);  
    anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {  
        @Override  
        public void onAnimationUpdate(ValueAnimator animation) {  
            currentPoint = (Point) animation.getAnimatedValue();  
            invalidate();  
        }  
    });  
    anim.setInterpolator(new DecelerateAccelerateInterpolator());  
    anim.setDuration(3000);  
    anim.start();  
}  

非常簡(jiǎn)單症革,就是將DecelerateAccelerateInterpolator的實(shí)例傳入到setInterpolator()方法當(dāng)中筐咧。重新運(yùn)行一下代碼,效果如下圖所示:

OK!小球的運(yùn)動(dòng)確實(shí)是先減速后加速的效果量蕊,說(shuō)明我們自定義的Interpolator已經(jīng)可以正常工作了铺罢。通過(guò)這樣一個(gè)程度的學(xué)習(xí),相信大家對(duì)屬性動(dòng)畫Interpolator的理解和使用都達(dá)到了一個(gè)比較深刻的層次了残炮。

ViewPropertyAnimator的用法

ViewPropertyAnimator其實(shí)算不上什么高級(jí)技巧韭赘,它的用法格外的簡(jiǎn)單,只不過(guò)和前面所學(xué)的所有屬性動(dòng)畫的知識(shí)不同势就,它并不是在3.0系統(tǒng)當(dāng)中引入的辞居,而是在3.1系統(tǒng)當(dāng)中附增的一個(gè)新的功能,因此這里我們把它作為整個(gè)屬性動(dòng)畫系列的收尾部分蛋勺。

我們都知道,屬性動(dòng)畫的機(jī)制已經(jīng)不是再針對(duì)于View而進(jìn)行設(shè)計(jì)的了鸠删,而是一種不斷地對(duì)值進(jìn)行操作的機(jī)制抱完,它可以將值賦值到指定對(duì)象的指定屬性上。但是刃泡,在絕大多數(shù)情況下巧娱,我相信大家主要都還是對(duì)View進(jìn)行動(dòng)畫操作的。Android開發(fā)團(tuán)隊(duì)也是意識(shí)到了這一點(diǎn)烘贴,沒有為View的動(dòng)畫操作提供一種更加便捷的用法確實(shí)是有點(diǎn)太不人性化了禁添,于是在Android 3.1系統(tǒng)當(dāng)中補(bǔ)充了ViewPropertyAnimator這個(gè)機(jī)制。

那我們先來(lái)回顧一下之前的用法吧桨踪,比如我們想要讓一個(gè)TextView從常規(guī)狀態(tài)變成透明狀態(tài)老翘,就可以這樣寫:

ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 0f);  
animator.start();  

看上去復(fù)雜嗎?好像也不怎么復(fù)雜锻离,但確實(shí)也不怎么容易理解铺峭。我們要將操作的view、屬性汽纠、變化的值都一起傳入到ObjectAnimator.ofFloat()方法當(dāng)中卫键,雖然看上去也沒寫幾行代碼,但這不太像是我們平時(shí)使用的面向?qū)ο蟮乃季S虱朵。
那么下面我們就來(lái)看一下如何使用ViewPropertyAnimator來(lái)實(shí)現(xiàn)同樣的效果莉炉,ViewPropertyAnimator提供了更加易懂、更加面向?qū)ο蟮腁PI碴犬,如下所示:

textview.animate().alpha(0f);  

果然非常簡(jiǎn)單絮宁!不過(guò)textview.animate()這個(gè)方法是怎么回事呢?animate()方法就是在Android 3.1系統(tǒng)上新增的一個(gè)方法服协,這個(gè)方法的返回值是一個(gè)ViewPropertyAnimator對(duì)象羞福,也就是說(shuō)拿到這個(gè)對(duì)象之后我們就可以調(diào)用它的各種方法來(lái)實(shí)現(xiàn)動(dòng)畫效果了,這里我們調(diào)用了alpha()方法并轉(zhuǎn)入0蚯涮,表示將當(dāng)前的textview變成透明狀態(tài)治专。

怎么樣卖陵?比起使用ObjectAnimator,ViewPropertyAnimator的用法明顯更加簡(jiǎn)單易懂吧张峰。除此之外泪蔫,ViewPropertyAnimator還可以很輕松地將多個(gè)動(dòng)畫組合到一起,比如我們想要讓textview運(yùn)動(dòng)到500,500這個(gè)坐標(biāo)點(diǎn)上喘批,就可以這樣寫:

textview.animate().x(500).y(500);  

可以看出撩荣,ViewPropertyAnimator是支持連綴用法的,我們想讓textview移動(dòng)到橫坐標(biāo)500這個(gè)位置上時(shí)調(diào)用了x(500)這個(gè)方法饶深,然后讓textview移動(dòng)到縱坐標(biāo)500這個(gè)位置上時(shí)調(diào)用了y(500)這個(gè)方法餐曹,將所有想要組合的動(dòng)畫通過(guò)這種連綴的方式拼接起來(lái),這樣全部動(dòng)畫就都會(huì)一起被執(zhí)行敌厘。
那么怎樣去設(shè)定動(dòng)畫的運(yùn)行時(shí)長(zhǎng)呢台猴?很簡(jiǎn)單,也是通過(guò)連綴的方式設(shè)定即可俱两,比如我們想要讓動(dòng)畫運(yùn)行5秒鐘饱狂,就可以這樣寫:

textview.animate().x(500).y(500).setDuration(5000);  

除此之外,本篇文章第一部分所學(xué)的Interpolator技術(shù)我們也可以應(yīng)用在ViewPropertyAnimator上面宪彩,如下所示:

textview.animate().x(500).y(500).setDuration(5000)  
        .setInterpolator(new BounceInterpolator());  

用法很簡(jiǎn)單休讳,同樣也是使用連綴的方式。相信大家現(xiàn)在都已經(jīng)體驗(yàn)出來(lái)了尿孔,ViewPropertyAnimator其實(shí)并沒有什么太多的技巧可言俊柔,用法基本都是大同小異的,需要用到什么功能就連綴一下活合,因此更多的用法大家只需要去查閱一下文檔婆咸,看看還支持哪些功能,有哪些接口可以調(diào)用就可以了芜辕。
那么除了用法之外尚骄,關(guān)于ViewPropertyAnimator有幾個(gè)細(xì)節(jié)還是值得大家注意一下的:

  • 整個(gè)ViewPropertyAnimator的功能都是建立在View類新增的animate()方法之上的,這個(gè)方法會(huì)創(chuàng)建并返回一個(gè)ViewPropertyAnimator的實(shí)例侵续,之后的調(diào)用的所有方法倔丈,設(shè)置的所有屬性都是通過(guò)這個(gè)實(shí)例完成的。
  • 大家注意到状蜗,在使用ViewPropertyAnimator時(shí)需五,我們自始至終沒有調(diào)用過(guò)start()方法,這是因?yàn)樾碌慕涌谥惺褂昧穗[式啟動(dòng)動(dòng)畫的功能轧坎,只要我們將動(dòng)畫定義完成之后宏邮,動(dòng)畫就會(huì)自動(dòng)啟動(dòng)。并且這個(gè)機(jī)制對(duì)于組合動(dòng)畫也同樣有效,只要我們不斷地連綴新的方法蜜氨,那么動(dòng)畫就不會(huì)立刻執(zhí)行械筛,等到所有在ViewPropertyAnimator上設(shè)置的方法都執(zhí)行完畢后,動(dòng)畫就會(huì)自動(dòng)啟動(dòng)飒炎。當(dāng)然如果不想使用這一默認(rèn)機(jī)制的話埋哟,我們也可以顯式地調(diào)用start()方法來(lái)啟動(dòng)動(dòng)畫。
  • ViewPropertyAnimator的所有接口都是使用連綴的語(yǔ)法來(lái)設(shè)計(jì)的郎汪,每個(gè)方法的返回值都是它自身的實(shí)例赤赊,因此調(diào)用完一個(gè)方法之后可以直接連綴調(diào)用它的另一個(gè)方法,這樣把所有的功能都串接起來(lái)煞赢,我們甚至可以僅通過(guò)一行代碼就完成任意復(fù)雜度的動(dòng)畫功能抛计。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市照筑,隨后出現(xiàn)的幾起案子吹截,更是在濱河造成了極大的恐慌,老刑警劉巖朦肘,帶你破解...
    沈念sama閱讀 206,723評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異双饥,居然都是意外死亡媒抠,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門咏花,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)趴生,“玉大人,你說(shuō)我怎么就攤上這事昏翰〔源遥” “怎么了?”我有些...
    開封第一講書人閱讀 152,998評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵棚菊,是天一觀的道長(zhǎng)浸踩。 經(jīng)常有香客問(wèn)我,道長(zhǎng)统求,這世上最難降的妖魔是什么检碗? 我笑而不...
    開封第一講書人閱讀 55,323評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮码邻,結(jié)果婚禮上折剃,老公的妹妹穿的比我還像新娘。我一直安慰自己像屋,他們只是感情好怕犁,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,355評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般奏甫。 火紅的嫁衣襯著肌膚如雪戈轿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,079評(píng)論 1 285
  • 那天扶檐,我揣著相機(jī)與錄音凶杖,去河邊找鬼。 笑死款筑,一個(gè)胖子當(dāng)著我的面吹牛智蝠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播奈梳,決...
    沈念sama閱讀 38,389評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼杈湾,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了攘须?” 一聲冷哼從身側(cè)響起漆撞,我...
    開封第一講書人閱讀 37,019評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎于宙,沒想到半個(gè)月后浮驳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,519評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡捞魁,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,971評(píng)論 2 325
  • 正文 我和宋清朗相戀三年至会,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片谱俭。...
    茶點(diǎn)故事閱讀 38,100評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡奉件,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出昆著,到底是詐尸還是另有隱情县貌,我是刑警寧澤,帶...
    沈念sama閱讀 33,738評(píng)論 4 324
  • 正文 年R本政府宣布凑懂,位于F島的核電站煤痕,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏接谨。R本人自食惡果不足惜杭攻,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,293評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望疤坝。 院中可真熱鬧兆解,春花似錦、人聲如沸跑揉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至现拒,卻和暖如春辣垒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背印蔬。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工勋桶, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人侥猬。 一個(gè)月前我還...
    沈念sama閱讀 45,547評(píng)論 2 354
  • 正文 我出身青樓例驹,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親退唠。 傳聞我的和親對(duì)象是個(gè)殘疾皇子鹃锈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,834評(píng)論 2 345

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

  • 【Android 動(dòng)畫】 動(dòng)畫分類補(bǔ)間動(dòng)畫(Tween動(dòng)畫)幀動(dòng)畫(Frame 動(dòng)畫)屬性動(dòng)畫(Property ...
    Rtia閱讀 6,103評(píng)論 1 38
  • 動(dòng)畫基礎(chǔ)概念 動(dòng)畫分類 Android 中動(dòng)畫分為兩種,一種是 Tween 動(dòng)畫瞧预、還有一種是 Frame 動(dòng)畫屎债。 ...
    Rtia閱讀 1,215評(píng)論 0 6
  • 1 背景 不能只分析源碼呀,分析的同時(shí)也要整理歸納基礎(chǔ)知識(shí)垢油,剛好有人微博私信讓全面說(shuō)說(shuō)Android的動(dòng)畫盆驹,所以今...
    未聞椛洺閱讀 2,693評(píng)論 0 10
  • 就像動(dòng)物,是由細(xì)胞組成的生命體滩愁,云也是由一個(gè)一個(gè)水珠組成的生命體躯喇。 云和動(dòng)物的區(qū)別就是,物有固態(tài)惊楼,云無(wú)常形...
    阿語(yǔ)魚雨閱讀 286評(píng)論 1 2
  • 春天真是個(gè)荷爾蒙格外美好的季節(jié)檀咙,朋友圈有一半人在刷健身,另外一半人在刷美食璃诀。 健身到一定階段弧可,我更愿意把“減肥”稱...
    本白啟食錄閱讀 908評(píng)論 4 17