簡介
成都創(chuàng)新互聯(lián)公司是一家集網(wǎng)站建設(shè),鷹手營子企業(yè)網(wǎng)站建設(shè),鷹手營子品牌網(wǎng)站建設(shè),網(wǎng)站定制,鷹手營子網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營銷,網(wǎng)絡(luò)優(yōu)化,鷹手營子網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競爭力。可充分滿足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶成長自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。
Android 開發(fā)中,總是需要一些動(dòng)畫來優(yōu)化用戶的交互體驗(yàn),提高用戶滿意度。因此,Google 為我們提供了一些用于處理動(dòng)畫效果的動(dòng)畫框架。Android 的動(dòng)畫框架分為兩類:
傳統(tǒng)動(dòng)畫框架的局限性
既然有了傳統(tǒng)動(dòng)畫框架,Google 為什么還要?jiǎng)?chuàng)造一個(gè)屬性動(dòng)畫框架呢?
我們下面舉個(gè)例子來說明一下傳統(tǒng)動(dòng)畫的局限性。
在布局中加入一個(gè) ImageView 和一個(gè) Button,點(diǎn)擊 ImageView 后彈出一個(gè) Toast,點(diǎn)擊 Button 后使 ImageView 展現(xiàn)一個(gè)向右平移的動(dòng)畫效果。
下面是使用傳統(tǒng)動(dòng)畫實(shí)現(xiàn)的代碼:
TranslateAnimation animation = new TranslateAnimation(0,200,0,0); // 平移動(dòng)畫x軸移動(dòng)200,y軸不動(dòng) animation.setDuration(1000); // 動(dòng)畫時(shí)長 animation.setFillAfter(true); // 使動(dòng)畫結(jié)束后停留在結(jié)束的位置 mIvPicture.startAnimation(animation);
運(yùn)行后,ImageView 確實(shí)進(jìn)行了我們預(yù)期的平移的效果。可是當(dāng)我們嘗試點(diǎn)擊 ImageView 當(dāng)前的位置時(shí),卻沒有 Toast 彈出。我們再嘗試去點(diǎn)擊 ImageView 開始動(dòng)畫前的位置,卻成功彈出了 Toast。
這就是傳統(tǒng)動(dòng)畫很大的局限性:
因此,Google 為我們提供了一套全新的屬性動(dòng)畫框架,來讓我們實(shí)現(xiàn)更豐富的動(dòng)畫效果。
ObjectAnimator
ObjectAnimator 是屬性動(dòng)畫中,最簡單也最常用的一個(gè)對象。
實(shí)現(xiàn) Animation 框架的功能
平移
前文提到的使 ImageVIew 向右平移 200 像素的動(dòng)畫效果,使用屬性動(dòng)畫只需要很簡單的幾句代碼即可實(shí)現(xiàn):
ObjectAnimator.ofFloat(mIvPicture,"translationX",0F,200F) .setDuration(1000) .start();
我們來分析一下這一句代碼。我們調(diào)用了ofFloat代碼,并傳入三個(gè)參數(shù)。
第一個(gè)參數(shù)是動(dòng)畫需要操縱的目標(biāo),在這里是我們的 ImageView。
第二個(gè)參數(shù)是所需要操縱的目標(biāo)所具備的屬性名稱。
第三個(gè)參數(shù)是這個(gè)動(dòng)畫變化的取值范圍。
最后設(shè)置一下它的動(dòng)畫的屬性,便可以 start 了。
這次我們再次點(diǎn)擊 ImageView 目前的位置,成功地彈出了 Toast。這證實(shí)了屬性動(dòng)畫是通過改變物體的屬性來達(dá)到動(dòng)畫效果的理論。
當(dāng)我們需要改變 y 坐標(biāo)時(shí),只需要把 "translationX" 變?yōu)?"translationY" 即可。
其實(shí) ,只要Google對一個(gè)對象的某個(gè)屬性提供了get和set方法,我們就可以使用這個(gè)屬性來實(shí)現(xiàn)動(dòng)畫效果。
其實(shí)我們還能用 X Y 兩個(gè)屬性實(shí)現(xiàn)之前的動(dòng)畫效果,那么對象屬性中 X 的 Y 與 translationX translationY 有什么區(qū)別呢?
translationX translationY指的是物體的偏移量,而X Y則表示它最終到達(dá)的絕對位置。
旋轉(zhuǎn)
旋轉(zhuǎn)屬性使用的是 "rotation" 屬性,后面的變換范圍的單位是角度。
比如想讓 ImageView 旋轉(zhuǎn)90度,只需要
ObjectAnimator.ofFloat(mIvPicture,"rotation",0F,90F) .setDuration(1000) .start();
其他
其實(shí)屬性動(dòng)畫能操縱的屬性,只要具有 set、get 方法,都可以進(jìn)行操縱。如 scaleX、scaleY 等等...
插值器
Android 為我們內(nèi)置了插值器,使我們的動(dòng)畫更為自然。比如可以讓我們的平移動(dòng)畫像物體的重力加速度由快到慢的 Accelerate 等等
Android中內(nèi)置了七種插值器,分別是
要應(yīng)用插值器,可以調(diào)用 ObjectAnimator 的 setInterpolator 方法, new 出對應(yīng)的插值器作為參數(shù)(xxxInterpolator)。比如下面這段代碼:
animator.setInterpolator(new AccelerateInterpolator());
通過插值器,我們可以讓動(dòng)畫的效果更佳自然。
多種屬性動(dòng)畫同時(shí)作用
當(dāng)我們把幾種動(dòng)畫按順序?qū)懴聲r(shí),運(yùn)行程序,會(huì)發(fā)現(xiàn)效果是三種屬性動(dòng)畫的疊加。由此可以發(fā)現(xiàn),屬性動(dòng)畫在調(diào)用 start 方法后,實(shí)際上是一個(gè)異步的過程。因此我們就可以看到三個(gè)屬性動(dòng)畫同時(shí)作用的效果。通過這樣的方法,其實(shí)就可以實(shí)現(xiàn)多種屬性動(dòng)畫同時(shí)作用的效果:
ObjectAnimator.ofFloat(mIvPicture,"translationX",0F,200F).setDuration(1000).start(); ObjectAnimator.ofFloat(mIvPicture,"rotationX",0F,360F).setDuration(1000).start(); ObjectAnimator.ofFloat(mIvPicture,"translationY",0F,200F).setDuration(1000).start();
其實(shí) Google 為我們提供了更好的方法,來實(shí)現(xiàn)這樣的效果。
我們可以使用 PropertyValuesHolder 來實(shí)現(xiàn)。其構(gòu)造函數(shù)僅僅比 ObjectAnimator 少了一個(gè)作用對象參數(shù)。之后通過ObjectAnimator 的 ofPropertyValuesHolder 方法,傳入作用對象以及要同時(shí)作用的 PropertyValuesHolder 即可執(zhí)行。可以看到下面的代碼示例:
PropertyValuesHolder p1 = PropertyValuesHolder.ofFloat("translationX",0F,200F); PropertyValuesHolder p2 = PropertyValuesHolder.ofFloat("rotationX",0F,360F); PropertyValuesHolder p3 = PropertyValuesHolder.ofFloat("translationY",0F,200F); ObjectAnimator.ofPropertyValuesHolder(mIvPicture,p1,p2,p3).setDuration(1000).start();
運(yùn)行后可以發(fā)現(xiàn),與之前的效果是相同的。
那既然兩種方法效果一樣,這樣相比之前有什么好處么?
AnimatorSet 屬性集合
playTogether 方法
我們其實(shí)還可以通過 AnimatorSet,來實(shí)現(xiàn)同樣的效果。這里我們調(diào)用了 set 的 playTogether 方法,使得這些方法同時(shí)執(zhí)行:
AnimatorSet set = new AnimatorSet(); ObjectAnimator animator1 = ObjectAnimator.ofFloat(mIvPicture, "translationX", 0F, 200F); ObjectAnimator animator2 = ObjectAnimator.ofFloat(mIvPicture, "rotationX", 0F, 360F); ObjectAnimator animator3 = ObjectAnimator.ofFloat(mIvPicture, "translationY", 0F, 200F); set.playTogether(animator1,animator2,animator3); set.setDuration(1000); set.start();
playSequentially方法
除了 playTogether 方法外,AnimatorSet 還提供了 playSequentially 方法,它可以使得動(dòng)畫按順序執(zhí)行。具體順序取決于調(diào)用時(shí)的參數(shù)順序。
AnimatorSet set = new AnimatorSet(); ObjectAnimator animator1 = ObjectAnimator.ofFloat(mIvPicture, "translationX", 0F, 200F); ObjectAnimator animator2 = ObjectAnimator.ofFloat(mIvPicture, "rotationX", 0F, 360F); ObjectAnimator animator3 = ObjectAnimator.ofFloat(mIvPicture, "translationY", 0F, 200F); set.playSequentially(animator1,animator2,animator3); set.setDuration(1000); set.start();
play 與 with、after 方法
我們除了可以用上述方法來讓動(dòng)畫按順序執(zhí)行外,也可以通過 AnimatorSet 的 play、with、after、before 等方法相組合來控制動(dòng)畫播放關(guān)系。
例如如下的代碼就可以實(shí)現(xiàn)先平移,再旋轉(zhuǎn)的效果
set.play(animator1).with(animator3); set.play(animator2).after(animator1);
動(dòng)畫監(jiān)聽事件
通過下面的代碼,我們可以實(shí)現(xiàn)按鈕按下后漸隱的效果。
mBtnPress.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { ObjectAnimator animator = ObjectAnimator.ofFloat(mBtnPress,"alpha",1F,0F); animator.setDuration(1000); animator.start(); } });
但如果我們想要在動(dòng)畫播放完成后再執(zhí)行一些操作的話,又該如何實(shí)現(xiàn)呢?
AnimatorListener
一個(gè)AnimatorListener,需要實(shí)現(xiàn)四個(gè)方法,分別是:
它們的回調(diào)時(shí)機(jī)我們根據(jù)字面意思便可以理解。大部分時(shí)候,我們需要實(shí)現(xiàn)的是onAnimationEnd方法。
animator.addListener(new AnimatorListener() { @Override public void onAnimationStart(Animator animation) { } @Override public void onAnimationEnd(Animator animation) { Toast.makeText(MainActivity.this,"Animation End",Toast.LENGTH_SHORT).show(); } @Override public void onAnimationCancel(Animator animation) { } @Override public void onAnimationRepeat(Animator animation) { } });
AnimatorListenerAdapter
如果每次監(jiān)聽都需要實(shí)現(xiàn)這么多方法,未免太麻煩了一點(diǎn)。因此 Android 為我們提供了另一種方法來添加動(dòng)畫的監(jiān)聽事件:在添加 AnimatorListener 的時(shí)候,傳入 AnimatorListenerAdapter 即可。這樣我們就只需要實(shí)現(xiàn)自己需要的方法即可。
animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); Toast.makeText(MainActivity.this,"Animation End",Toast.LENGTH_SHORT).show(); } });
ValueAnimator
簡介
ValueAnimator 本身不作用于任何一個(gè)屬性,也不提供任何一種動(dòng)畫。它就是一個(gè)數(shù)值發(fā)生器,可以產(chǎn)生想要的各種數(shù)值。Android 系統(tǒng)為它提供了很多計(jì)算數(shù)值的方法,如 int、float 等等。我們也可以自己實(shí)現(xiàn)計(jì)算數(shù)值的方法。其實(shí),在屬性動(dòng)畫中,如何產(chǎn)生每一步的動(dòng)畫效果,都是通過 ValueAnimator 計(jì)算出來的。
比如我們要實(shí)現(xiàn)一個(gè)從 0-100 的位移動(dòng)畫。隨著動(dòng)畫時(shí)間的持續(xù),它產(chǎn)生的值也會(huì)從 0-100 遞增。通過這個(gè) ValueAnimator 產(chǎn)生的值,再進(jìn)行屬性的設(shè)置即可。
那么 ValueAnimator 究竟是如何產(chǎn)生這些值的呢?
由于 ValueAnimator 不作用于任何一個(gè)屬性,也不提供任何一種動(dòng)畫。因此并沒有 ObjectAnimator 使用得廣泛。
實(shí)際上,ObjectAnimator 就是基于 ValueAnimator 進(jìn)行的一次封裝。我們可以查看 ObjectAnimator 的源碼,會(huì)發(fā)現(xiàn)它繼承自 ValueAnimator,是它的一個(gè)子類。正是 ValueAnimator 產(chǎn)生的變化值,才使得 ObjectAnimator 可以將它應(yīng)用于各個(gè)屬性。
使用方法
我們可以通過 ValueAnimator 的 ofXXX 產(chǎn)生一個(gè) XXX 類型的值(如ofInt),然后為 ValueAnimator 添加一個(gè)更新的回調(diào)事件。在回調(diào)事件中,通過參數(shù) animation 的 getAnimationValue() 方法,來獲取對應(yīng)的 value。有了這個(gè)值,我們就可以實(shí)現(xiàn)我們所有想要的動(dòng)畫效果。
比如此處就通過 ValueAnimator 實(shí)現(xiàn)了一個(gè)計(jì)時(shí)器的動(dòng)畫效果。
ValueAnimator animator = ValueAnimator.ofInt(0,100); animator.setDuration(5000); animator.addUpdateListener(new AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { Integer value = (Integer) animation.getAnimatedValue(); mButton.setText(""+value); } }); animator.start();
自定義數(shù)值生成器
前面提到,ValueAnimator 可以創(chuàng)建自定義的數(shù)值生成器,做法就是調(diào)用 ValueAnimator 的 ofObject 方法,創(chuàng)建一個(gè) TypeEvaluator 作為參數(shù)。之后我們可以通過重寫 TypeEvaluator 的 evaluate 方法,來按照自己的規(guī)則返回具體的值。
ValueAnimator animator = ValueAnimator.ofObject(new TypeEvaluator() { @Override public Object evaluate(float fraction, Object startValue, Object endValue) { //計(jì)算 return null; //返回值 } });
我們來看一下 evaluate 方法的幾個(gè)參數(shù)
通過這三個(gè)值,我們就可以經(jīng)過計(jì)算產(chǎn)生所有我們想要的值。
其實(shí),通過 TypeEvaluator,我們不光能產(chǎn)生普通的數(shù)據(jù),還能結(jié)合泛型,我們還能定義更加復(fù)雜的數(shù)據(jù):
我們可以在創(chuàng)建 TypeEvaluator 時(shí)指定具體類型,來達(dá)到更豐富的效果。比如這里就用到了一個(gè)名為 PointF 的數(shù)據(jù)類型:
ValueAnimator animator = ValueAnimator.ofObject(new TypeEvaluator() { @Override public PointF evaluate(float fraction, PointF startValue, PointF endValue) { //計(jì)算 return null; //返回值 } });
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對創(chuàng)新互聯(lián)的支持。