欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android動(dòng)畫(huà)教程之屬性動(dòng)畫(huà)詳解

 更新時(shí)間:2019年05月09日 10:42:52   作者:被被的安卓編程之路  
這篇文章主要給大家介紹了關(guān)于Android動(dòng)畫(huà)教程之屬性動(dòng)畫(huà)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)各位Android開(kāi)發(fā)者們具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

簡(jiǎn)介

Android 開(kāi)發(fā)中,總是需要一些動(dòng)畫(huà)來(lái)優(yōu)化用戶的交互體驗(yàn),提高用戶滿意度。因此,Google 為我們提供了一些用于處理動(dòng)畫(huà)效果的動(dòng)畫(huà)框架。Android 的動(dòng)畫(huà)框架分為兩類:

  • 傳統(tǒng)動(dòng)畫(huà)(Animation):通過(guò)系統(tǒng)不斷調(diào)用onDraw方法重繪界面,來(lái)達(dá)到動(dòng)畫(huà)的效果。
  • 屬性動(dòng)畫(huà)(Animator):通過(guò)操縱一個(gè)屬性的get/set方法,真實(shí)地改變目標(biāo)的某些屬性。

傳統(tǒng)動(dòng)畫(huà)框架的局限性

既然有了傳統(tǒng)動(dòng)畫(huà)框架,Google 為什么還要?jiǎng)?chuàng)造一個(gè)屬性動(dòng)畫(huà)框架呢?

我們下面舉個(gè)例子來(lái)說(shuō)明一下傳統(tǒng)動(dòng)畫(huà)的局限性。

在布局中加入一個(gè) ImageView 和一個(gè) Button,點(diǎn)擊 ImageView 后彈出一個(gè) Toast,點(diǎn)擊 Button 后使 ImageView 展現(xiàn)一個(gè)向右平移的動(dòng)畫(huà)效果。

下面是使用傳統(tǒng)動(dòng)畫(huà)實(shí)現(xiàn)的代碼:

TranslateAnimation animation = new TranslateAnimation(0,200,0,0); // 平移動(dòng)畫(huà)x軸移動(dòng)200,y軸不動(dòng)
animation.setDuration(1000); // 動(dòng)畫(huà)時(shí)長(zhǎng)
animation.setFillAfter(true); // 使動(dòng)畫(huà)結(jié)束后停留在結(jié)束的位置
mIvPicture.startAnimation(animation);

運(yùn)行后,ImageView 確實(shí)進(jìn)行了我們預(yù)期的平移的效果。可是當(dāng)我們嘗試點(diǎn)擊 ImageView 當(dāng)前的位置時(shí),卻沒(méi)有 Toast 彈出。我們?cè)賴L試去點(diǎn)擊 ImageView 開(kāi)始動(dòng)畫(huà)前的位置,卻成功彈出了 Toast。

這就是傳統(tǒng)動(dòng)畫(huà)很大的局限性:

  • 它僅僅是重繪了控件,改變了其顯示的位置。但真正事件響應(yīng)的位置,卻并沒(méi)有發(fā)生改變。因此傳統(tǒng)動(dòng)畫(huà)不適合做具有交互的動(dòng)畫(huà)效果。僅僅能做一些顯示的動(dòng)畫(huà)效果。
  • 傳統(tǒng)動(dòng)畫(huà)是不斷通過(guò) onDraw() 方法重繪界面,必然會(huì)十分耗費(fèi)GPU資源。
  • 傳統(tǒng)動(dòng)畫(huà)所支持的動(dòng)畫(huà)類型少,僅有旋轉(zhuǎn)、縮放、位移、透明度這四種動(dòng)畫(huà)效果。雖然通過(guò)組合可以實(shí)現(xiàn)豐富的效果,但相比直接通過(guò)改變屬性來(lái)實(shí)現(xiàn)的屬性動(dòng)畫(huà)來(lái)說(shuō),還是有很大的局限性的。

因此,Google 為我們提供了一套全新的屬性動(dòng)畫(huà)框架,來(lái)讓我們實(shí)現(xiàn)更豐富的動(dòng)畫(huà)效果。

ObjectAnimator

ObjectAnimator 是屬性動(dòng)畫(huà)中,最簡(jiǎn)單也最常用的一個(gè)對(duì)象。

實(shí)現(xiàn) Animation 框架的功能

平移

前文提到的使 ImageVIew 向右平移 200 像素的動(dòng)畫(huà)效果,使用屬性動(dòng)畫(huà)只需要很簡(jiǎn)單的幾句代碼即可實(shí)現(xiàn):

ObjectAnimator.ofFloat(mIvPicture,"translationX",0F,200F)
 .setDuration(1000)
 .start();

我們來(lái)分析一下這一句代碼。我們調(diào)用了ofFloat代碼,并傳入三個(gè)參數(shù)。

​ 第一個(gè)參數(shù)是動(dòng)畫(huà)需要操縱的目標(biāo),在這里是我們的 ImageView。

​ 第二個(gè)參數(shù)是所需要操縱的目標(biāo)所具備的屬性名稱。

​ 第三個(gè)參數(shù)是這個(gè)動(dòng)畫(huà)變化的取值范圍。

最后設(shè)置一下它的動(dòng)畫(huà)的屬性,便可以 start 了。

這次我們?cè)俅吸c(diǎn)擊 ImageView 目前的位置,成功地彈出了 Toast。這證實(shí)了屬性動(dòng)畫(huà)是通過(guò)改變物體的屬性來(lái)達(dá)到動(dòng)畫(huà)效果的理論。

當(dāng)我們需要改變 y 坐標(biāo)時(shí),只需要把 "translationX" 變?yōu)?"translationY" 即可。

其實(shí) ,只要Google對(duì)一個(gè)對(duì)象的某個(gè)屬性提供了get和set方法,我們就可以使用這個(gè)屬性來(lái)實(shí)現(xiàn)動(dòng)畫(huà)效果。

其實(shí)我們還能用 X Y 兩個(gè)屬性實(shí)現(xiàn)之前的動(dòng)畫(huà)效果,那么對(duì)象屬性中 X 的 Y 與 translationX translationY 有什么區(qū)別呢?

translationX translationY指的是物體的偏移量,而X Y則表示它最終到達(dá)的絕對(duì)位置。

旋轉(zhuǎn)

旋轉(zhuǎn)屬性使用的是 "rotation" 屬性,后面的變換范圍的單位是角度。

比如想讓 ImageView 旋轉(zhuǎn)90度,只需要

ObjectAnimator.ofFloat(mIvPicture,"rotation",0F,90F)
 .setDuration(1000)
 .start();

其他

其實(shí)屬性動(dòng)畫(huà)能操縱的屬性,只要具有 set、get 方法,都可以進(jìn)行操縱。如 scaleX、scaleY 等等...

插值器

Android 為我們內(nèi)置了插值器,使我們的動(dòng)畫(huà)更為自然。比如可以讓我們的平移動(dòng)畫(huà)像物體的重力加速度由快到慢的 Accelerate 等等

Android中內(nèi)置了七種插值器,分別是

  • Accelerate
  • Decelerate
  • Accelerate/Decelerate
  • Anticipate
  • Overshoot
  • Anticipate/Overshoot
  • Bounce

要應(yīng)用插值器,可以調(diào)用 ObjectAnimator 的 setInterpolator 方法, new 出對(duì)應(yīng)的插值器作為參數(shù)(xxxInterpolator)。比如下面這段代碼:

animator.setInterpolator(new AccelerateInterpolator());

通過(guò)插值器,我們可以讓動(dòng)畫(huà)的效果更佳自然。

多種屬性動(dòng)畫(huà)同時(shí)作用

當(dāng)我們把幾種動(dòng)畫(huà)按順序?qū)懴聲r(shí),運(yùn)行程序,會(huì)發(fā)現(xiàn)效果是三種屬性動(dòng)畫(huà)的疊加。由此可以發(fā)現(xiàn),屬性動(dòng)畫(huà)在調(diào)用 start 方法后,實(shí)際上是一個(gè)異步的過(guò)程。因此我們就可以看到三個(gè)屬性動(dòng)畫(huà)同時(shí)作用的效果。通過(guò)這樣的方法,其實(shí)就可以實(shí)現(xiàn)多種屬性動(dòng)畫(huà)同時(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 為我們提供了更好的方法,來(lái)實(shí)現(xiàn)這樣的效果。

我們可以使用 PropertyValuesHolder 來(lái)實(shí)現(xiàn)。其構(gòu)造函數(shù)僅僅比 ObjectAnimator 少了一個(gè)作用對(duì)象參數(shù)。之后通過(guò)ObjectAnimator 的 ofPropertyValuesHolder 方法,傳入作用對(duì)象以及要同時(shí)作用的 PropertyValuesHolder 即可執(zhí)行??梢钥吹较旅娴拇a示例:

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),與之前的效果是相同的。

那既然兩種方法效果一樣,這樣相比之前有什么好處么?

  • 其實(shí) Google 在 PropertyValuesHolder 內(nèi)部進(jìn)行了一些優(yōu)化,使得我們使用多個(gè)屬性動(dòng)畫(huà)時(shí)更加有效率,節(jié)省系統(tǒng)資源。

AnimatorSet 屬性集合

playTogether 方法

我們其實(shí)還可以通過(guò) AnimatorSet,來(lái)實(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)畫(huà)按順序執(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 方法

我們除了可以用上述方法來(lái)讓動(dòng)畫(huà)按順序執(zhí)行外,也可以通過(guò) AnimatorSet 的 play、with、after、before 等方法相組合來(lái)控制動(dòng)畫(huà)播放關(guān)系。

例如如下的代碼就可以實(shí)現(xiàn)先平移,再旋轉(zhuǎn)的效果

set.play(animator1).with(animator3);
set.play(animator2).after(animator1);

動(dòng)畫(huà)監(jiān)聽(tīng)事件

通過(guò)下面的代碼,我們可以實(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)畫(huà)播放完成后再執(zhí)行一些操作的話,又該如何實(shí)現(xiàn)呢?

  • 我們可以使用 ObjectAnimator 的 addListener方法,傳入一個(gè)AnimatorListener,為動(dòng)畫(huà)設(shè)置監(jiān)聽(tīng)事件。

AnimatorListener

一個(gè)AnimatorListener,需要實(shí)現(xiàn)四個(gè)方法,分別是:

  • onAnimationStart
  • onAnimationEnd
  • onAnimationCancel
  • onAnimationRepeat

它們的回調(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)聽(tīng)都需要實(shí)現(xiàn)這么多方法,未免太麻煩了一點(diǎn)。因此 Android 為我們提供了另一種方法來(lái)添加動(dòng)畫(huà)的監(jiān)聽(tīng)事件:在添加 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

簡(jiǎn)介

ValueAnimator 本身不作用于任何一個(gè)屬性,也不提供任何一種動(dòng)畫(huà)。它就是一個(gè)數(shù)值發(fā)生器,可以產(chǎn)生想要的各種數(shù)值。Android 系統(tǒng)為它提供了很多計(jì)算數(shù)值的方法,如 int、float 等等。我們也可以自己實(shí)現(xiàn)計(jì)算數(shù)值的方法。其實(shí),在屬性動(dòng)畫(huà)中,如何產(chǎn)生每一步的動(dòng)畫(huà)效果,都是通過(guò) ValueAnimator 計(jì)算出來(lái)的。

比如我們要實(shí)現(xiàn)一個(gè)從 0-100 的位移動(dòng)畫(huà)。隨著動(dòng)畫(huà)時(shí)間的持續(xù),它產(chǎn)生的值也會(huì)從 0-100 遞增。通過(guò)這個(gè) ValueAnimator 產(chǎn)生的值,再進(jìn)行屬性的設(shè)置即可。

那么 ValueAnimator 究竟是如何產(chǎn)生這些值的呢?

  • 首先 ValueAnimator會(huì)根據(jù)會(huì)根據(jù)動(dòng)畫(huà)已進(jìn)行的時(shí)間與它持續(xù)的總時(shí)間的比值,產(chǎn)生一個(gè)0-1的時(shí)間因子。有了這樣的時(shí)間因子,經(jīng)過(guò)相應(yīng)的變換,就可以根據(jù)初始值和最終值來(lái)生成中間的相應(yīng)值。同時(shí),通過(guò)插值器的使用,我們還可以進(jìn)一步控制每一個(gè)時(shí)間因子產(chǎn)生值的變化速率。如果我們使用的是線性插值器,那么它生成值的時(shí)候就會(huì)呈一個(gè)線性變化。如果我們使用一個(gè)加速度插值器,那么它生成值時(shí)便會(huì)呈一個(gè)二次曲線,增長(zhǎng)率越來(lái)越快。

由于 ValueAnimator 不作用于任何一個(gè)屬性,也不提供任何一種動(dòng)畫(huà)。因此并沒(méi)有 ObjectAnimator 使用得廣泛。
實(shí)際上,ObjectAnimator 就是基于 ValueAnimator 進(jìn)行的一次封裝。我們可以查看 ObjectAnimator 的源碼,會(huì)發(fā)現(xiàn)它繼承自 ValueAnimator,是它的一個(gè)子類。正是 ValueAnimator 產(chǎn)生的變化值,才使得 ObjectAnimator 可以將它應(yīng)用于各個(gè)屬性。

使用方法

我們可以通過(guò) ValueAnimator 的 ofXXX 產(chǎn)生一個(gè) XXX 類型的值(如ofInt),然后為 ValueAnimator 添加一個(gè)更新的回調(diào)事件。在回調(diào)事件中,通過(guò)參數(shù) animation 的 getAnimationValue() 方法,來(lái)獲取對(duì)應(yīng)的 value。有了這個(gè)值,我們就可以實(shí)現(xiàn)我們所有想要的動(dòng)畫(huà)效果。

比如此處就通過(guò) ValueAnimator 實(shí)現(xiàn)了一個(gè)計(jì)時(shí)器的動(dòng)畫(huà)效果。

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ù)。之后我們可以通過(guò)重寫(xiě) TypeEvaluator 的 evaluate 方法,來(lái)按照自己的規(guī)則返回具體的值。

ValueAnimator animator = ValueAnimator.ofObject(new TypeEvaluator() {
 @Override
 public Object evaluate(float fraction, Object startValue, Object endValue) {
  //計(jì)算
  return null; //返回值
 }
});

我們來(lái)看一下 evaluate 方法的幾個(gè)參數(shù)

  • float fraction:前面提到的時(shí)間因子
  • Object startValue:起始值
  • Object endValue:結(jié)束值

通過(guò)這三個(gè)值,我們就可以經(jīng)過(guò)計(jì)算產(chǎn)生所有我們想要的值。

其實(shí),通過(guò) TypeEvaluator,我們不光能產(chǎn)生普通的數(shù)據(jù),還能結(jié)合泛型,我們還能定義更加復(fù)雜的數(shù)據(jù):

我們可以在創(chuàng)建 TypeEvaluator 時(shí)指定具體類型,來(lái)達(dá)到更豐富的效果。比如這里就用到了一個(gè)名為 PointF 的數(shù)據(jù)類型:

ValueAnimator animator = ValueAnimator.ofObject(new TypeEvaluator<PointF>() {
 @Override
 public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
  //計(jì)算
  return null; //返回值
 }
});

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

最新評(píng)論