Android動畫運用

談談動畫

動畫做爲展示動態效果不可缺乏的一環,仍是異常重要的,其主要運用在View中。 按照Android發展史能夠分紅三個大類:逐幀動畫、補間動畫、屬性動畫。 在如今的實際開發裏面,使用不少的仍是屬性動畫相關的東西,前兩種動畫已經不大經常使用,漸漸淡出了人們的視野。在這裏只是簡單介紹。html

逐幀動畫

這種原理就相似於gif圖,播放全部已有的幀,經過人眼的短暫視覺殘留來完成動畫。 等價於Android裏面的AnimationDrawablejava

利用XML進行定義

須要在 <animation-list .../> 標籤下使用 <item .../> 子元素標籤訂義動畫的所有幀(引入每一幀對應的資源文件),並指定各幀的持續時間。以完成目的。android

該文件建立在res/drawable文件目錄之下設計模式

<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="true|false">
      <item android:drawable="xxx" android:duration="xx"/>
      <!-- more... -->
 </animation-list>
複製代碼

其中oneshot表示該動畫是否循環播放,true表示只播放一次,false表示無限循環。app

以後在ImageView裏面設置對應的資源便可。 只須要獲取到對應的AnimationDrawable對象,便可經過start()以及stop()方法來控制動畫的開始與中止。ide

直接使用代碼定義

初始化AnimationDrawable對象後,經過addFrame(Drawable,int)來進行加入,分別表明對應幀和持續時間。 直接在ImageView裏面setDrawable()來進行綁定。 setOneShot(true)設置動畫是都循環播放。 一樣的,使用start()以及stop()方法來控制動畫的開始與中止。post

使用太多較大的圖片容易引發OOM動畫

補間動畫

顧名思義,就是開發者(咱們)只須要給出動畫的第一幀以及最後一幀,經過系統自動實現中間的過渡動做。ui

Android幫提供瞭如下的幾種屬性的動畫this

  • 透明度變換:Alpha
  • 位移:translate
  • 縮放:scale
  • 旋轉:rotate

能夠經過XML文件對他們進行設置,在代碼之中分別對應AlphaAnimation/TranslateAnimation/ScaleAnimation/RotateAnimation這四個類,共同父類爲Animation

具體的不會過多展開講解,可參考該博客

利用XML進行定義

須要將對應的資源文件放於目錄res/anim文件下

一些屬性:

  • duration 持續時間

  • interpolator 插值器,控制動畫的變化速率。

    Android裏面自帶如下實現:

    • AccelerateDecelerateInterpolator

      在動畫開始與結束的地方速率改變比較慢,在中間的時候加速

    • AccelerateInterpolator

      在動畫開始的地方速率改變比較慢,而後開始加速

    • AnticipateInterpolator

      開始的時候進行反向效果真後按照預期效果進行

    • AnticipateOvershootInterpolator

      開始的時候進行反向效果真後超出預期值後返回最後需求的狀態

    • BounceInterpolator

      動畫結束的時候會重複最後一小段時間內的動畫效果

    • CycleInterpolator

      動畫循環播放特定的次數,速率的大小改變聽從正弦曲線

    • DecelerateInterpolator

      在動畫開始快而後速率減少

    • LinearInterpolator

      勻速改變

    • OvershootInterpolator

      超出預期值後再回到最後的狀態

      這些插值器都可以經過@android.anim/xxx進行引用。

      含附錄:自帶插值器效果圖

  • fillAfter動畫結束後是否停留在結束位

而在對應的xml屬性之中,經過設定fromXxxtoXxx屬性來設定對應屬性的開始值和終點值。 以移動爲例:

<translate android:fromXDelta="0" android:toXDelta="100" android:fromYDelta="0" android:toYDelta="100" />
複製代碼

X和Y對應的是X方向與Y方向的操做。 其中對於透明度的設置範圍是-1.0-1.0 縮放值跟的是相對應的倍數,例如0.5是縮小一半,2.0是放大一倍 而後在rotate以及scale範圍裏面還有兩個參數pivotX/pivotY來表示操做的中心點(起始點) 對應的有幾種表示方式,以pivotX爲例子講解

  • 10:動畫開始X方向的點爲View左上角的點 在x方向 加上 10像素的位置
  • 10%: 動畫開始X方向的點View左上角的點 在x方向 加上 自身寬度乘上10%的位置
  • 10%p:動畫開始X方向的點離View左上角的點 在x方向 加上 父控件寬度乘上10%數值的位置

利用Java實現補間動畫

該方法經過實例化對應的動畫對象來進行相對應的設置。 這些動畫的使用都是調用View.startAnimation(anim)開始動畫 經過能夠經過setDuration(int)方法設置動畫運行的時間

  • translate
Animation translateAnimation = new TranslateAnimation(05000500);
/** * 1. fromXDelta :視圖在水平方向x 移動的起始值 * 2. toXDelta :視圖在水平方向x 移動的結束值 * 3. fromYDelta :視圖在豎直方向y 移動的起始值 * 4. toYDelta:視圖在豎直方向y 移動的結束值 */
複製代碼
  • scale
Animation scaleAnimation= new ScaleAnimation(0,2,0,2,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
 /** * 1. fromX :動畫在水平方向X的結束縮放倍數 * 2. toX :動畫在水平方向X的結束縮放倍數 * 3. fromY :動畫開始前在豎直方向Y的起始縮放倍數 * 4. toY:動畫在豎直方向Y的結束縮放倍數 * 5. pivotXType:縮放軸點的x座標的模式 * 6. pivotXValue:縮放軸點x座標的相對值 * 7. pivotYType:縮放軸點的y座標的模式 * 8. pivotYValue:縮放軸點y座標的相對值 * pivotXType = Animation.ABSOLUTE:縮放軸點的x座標 = View左上角的原點 在x方向 加上 pivotXValue數值的點(y方向同理) * pivotXType = Animation.RELATIVE_TO_SELF:縮放軸點的x座標 = View左上角的原點 在x方向 加上 自身寬度乘上pivotXValue數值的值(y方向同理) * pivotXType = Animation.RELATIVE_TO_PARENT:縮放軸點的x座標 = View左上角的原點 在x方向 加上 父控件寬度乘上pivotXValue數值的值 (y方向同理) */
複製代碼
  • Rotate
Animation rotateAnimation = new RotateAnimation(0,270,Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
/** * 1. fromDegrees :動畫開始時 視圖的旋轉角度(正數 = 順時針,負數 = 逆時針) * 2. toDegrees :動畫結束時 視圖的旋轉角度(正數 = 順時針,負數 = 逆時針) * 3. pivotXType:旋轉軸點的x座標的模式 * 4. pivotXValue:旋轉軸點x座標的相對值 * 5. pivotYType:旋轉軸點的y座標的模式 * 6. pivotYValue:旋轉軸點y座標的相對值 * pivotXType具體值以及做用同上 */
複製代碼
  • alpha
Animation alphaAnimation = new AlphaAnimation(1,0);
// 1. fromAlpha:動畫開始時視圖的透明度(取值範圍: -1 ~ 1)
// 2. toAlpha:動畫結束時視圖的透明度(取值範圍: -1 ~ 1)
複製代碼

動畫的設置優先級:子動畫>動畫集。即,子動畫設置了無限循環,動畫集設置了只運行一次,運行的時候仍是無限循環的模式。

固然,也能夠經過本身需求對補間動畫進行定義,繼承Animation類,並重寫applyTranformation()方法 具體的就不詳細講述了,由於:

咱們爲何不用屬性動畫呢?

屬性動畫

屬性動畫直白來講,是對任意對象的任意屬性進行動畫過渡,是補間動畫的增強版 其優勢:

  • 針對全部的對象
  • 改變了View的屬性值,在動畫的時候已經對應改變了view的屬性(響應點擊事件)
  • 可擴展性(自定義屬性效果)

咱們一般使用如下兩個類

  • ValueAnimator

    在屬性動畫裏面使用到的時間引擎,計算對應的屬性值

  • ObjectAnimator

    是上者的子類,對指定對象的屬性執行動畫

爲了健壯性,通常是在代碼裏面聲明對象,在這裏就不介紹XML設置的方式

ValueAnimator

經過不斷控制值的變化,在不斷手動賦值給對象的屬性,從而實現動畫效果。

過程:

  • 設置動畫的運行時長,動畫效果以及開始和結束的屬性值

  • 設置估值器

    該類描述動畫如何從初始值過渡到結束值的邏輯

  • 添加AnimatorUpdateListener,該接口會直接回調當前狀態的Animation,經過animation.getAnimatedValue()(記得強制轉換,由於該方法返回的是Object)獲取到當前的值

  • 將值設置到給須要進行變換的屬性上面

  • 通知View進行重繪

    • postInvalidate()
    • invalidate()

在這裏面主要是使用ValueAnimator.ofXxx(...values)靜態方法來獲取相對應的ValueAnimator 含有ofInt()/ofFloat()/ofObject()/ofArgb()/ofPropertyValuesHolder()這幾種方法 分別對應其中的過渡值:整形值、浮點值、對象、顏色值、存儲屬性的動畫改變值 實際開發裏面經常使用前面三種,在使用的時候傳入對應屬性的變化值

Animator animator = ValueAnimator.ofFloat(0, 3f);
// 設置運行時間
animator.setDuration((long) (time * 1000));
// 設置重複次數
animator.setRepeatCount(0);
// 設置重複播放動畫模式
// ValueAnimator.RESTART(默認):正序重放
// ValueAnimator.REVERSE:倒序回放
animmator.setRepeatMode(ValueAnimator.RESTART);
// 設置插值器
animator.setInterpolator(new LinearInterpolator());
// 添加監聽
animator.addUpdateListener(animation -> {
    float f = (float) animation.getAnimatedValue();
    // 對view進行操做
    postInvalidate();
});
animator.start();
複製代碼

可是對於對象的過渡,咱們須要自定義估值器(自定義類實現TypeEvaluator接口) 複寫evaluate(float fraction, Object startValue, Object endValue)方法 分別對應:

  • fraction:表示動畫完成度(根據它來計算當前動畫的值)
  • startValue、endValue:動畫的初始值和結束值

最後須要返回對象通過過渡邏輯計算後的值

本質上仍是在操做值,不過將多個值所有封裝到了一個對象裏面

ObjectAnimator

直接傳入對象以及對象的屬性名以及操做值來實現動畫效果

該類相比於ValueAnimator來講,只是少了賦值給對應屬性這一步

新建對象與ValueAnimator類似,也是經過ofXxx方法,不過傳入的參數有區別,加入了對應的新參數 (Object object, String property, ....values)

  • 操做對象
  • 操做屬性
  • 變化值

使用樣例以下

ObjectAnimator animator = ObjectAnimator.ofFloat(this, "translationX", 0, 200f);
animator.setDuration((long) (actionTime * 1000));
animator.start();
複製代碼

對於ofPropertyValuesHolder()來講,只須要傳入(Object,PropertyValuesHolder ... values)便可

PropertyValuesHolder

存放作動畫的對應屬性以及期間的變化值,聲明方式與ValueAnimator相似,不過在以前須要傳入屬性名

對於該類,在最開始有一個簡單解釋:

此類包含有關屬性的信息以及該屬性在動畫期間應採用的值。 PropertyValuesHolder對象可用於使用ValueAnimator或ObjectAnimator建立動畫,這些動畫可並行操做多個不一樣的屬性。

可等價於動畫集合AnimatorSet,在ObjectAnimatorValueAnimator之中調用並傳入參數便可。

PropertyValuesHolder upX = PropertyValuesHolder.ofFloat("translationX", 0, -20);
PropertyValuesHolder upY = PropertyValuesHolder.ofFloat("translationY", 0, -20);
ObjectAnimator animatorUp = ObjectAnimator.ofPropertyValuesHolder(this, upX, upY)
                .setDuration((long) (actionTime * 1000));
animatorUp.setStartDelay((long) (actionTime * 100));
animatorUp.start();
複製代碼

動畫監聽

除了AnimatorUpdateListener來監聽過程當中的值,也可以經過添加AnimatorListener來實現動畫過程的監聽以完成交互 實現該接口須要重寫如下方法:

  • onAnimationStart

    動畫開始時

  • onAnimationRepeat

    動畫重複時

  • onAnimationCancel

    動畫取消時

  • onAnimationEnd

    動畫結束時

Animation中經過addListener方法傳入。(動畫對象均可以調用addListener方法來實現監聽) AnimatorUpdateListener只可以用於ValueAnimator之中(只有該類暴露了設置的接口)

倘若重寫四個方法太繁瑣,可使用AnimatorListenerAdapter來指定複寫某方法

經過自定義對象屬性來實現動畫效果

前提:

  • 爲對象設置須要操做屬性的get以及set屬性 如下方法針對沒有直接的getset方法的狀況
    • 繼承原始類,對外暴露該屬性的getset
    • 用一個類來包裝原始對象,進行擴展(設計模式--裝飾模式)
  • 經過TypeEvaluator類實現屬性變化的邏輯
  • 調用ofObjecct()方法

手動設置對應屬性的時候,注意:

  • 對外暴露對應的set/get方法
  • 對應的set方法對該屬性的改變會經過某種方式反映出來 例如view.setWidth()view.getWidth()並不會完成預期效果

ViewPropertyAnimator

爲了面向對象而新增的一個類,能夠理解爲是屬性動畫的一種簡寫方式。

經過View.animate().xxx().xxx()進行鏈式調用。 在animate()方法後返回了一個ViewPropertyAnimator對象,以後全部方法都是在這個基礎上進行調用。

一個簡單例子:

view.animate().alpha(0f);
// 單個動畫設置:將按鈕變成透明狀態 
view.animate().alpha(0f).setDuration(3 * 1000).setInterpolator(new BounceInterpolator());
// 單個動畫效果設置以及參數設置 
view.animate().alpha(0f).x(50).y(50);
/** * 組合動畫:將按鈕變成透明狀態再移動到(50,50)處 * 特別注意: * 動畫會自啓動,無需調用start()方法.由於新的接口中使用了隱式啓動動畫的功能,只要咱們將動畫定義完成後,動畫就會自動啓動 * 該機制對於組合動畫也一樣有效,只要不斷地連綴新的方法,那麼動畫就不會馬上執行,等到全部在ViewPropertyAnimator上設置的方法都執行完畢後,動畫就會自啓動 */
複製代碼

AnimatorSet

承載一個動畫集合,能夠經過相關的方法調整展現的順序。play()內部調用Builder()方法建立對應的對象。 例如:

AnimatorSet s = new AnimatorSet();
s.play(anim1).with(anim2);
s.play(anim2).before(anim3);
s.play(anim4).after(anim3);
複製代碼

xml中使用<set ... />標籤來結合多個Animation後在代碼裏面經過如下方式加載動畫

// 加載動畫資源
Animation anim = AnimationUtils.loadAnimation(this,R.anim.xxx);
//設置動畫結束後保留結束狀態
anim.setFillAfter(true);
// 以後經過ImageView裏面的startAnimation進行動畫的開始
ImageView im = findViewById(xxx);
im.startAnimation(anim);
複製代碼

其餘動畫

layoutAnimation

針對於ViewGroup裏面的子元素,譬如說ListView

  • XML:<layoutanimation .../>
  • 代碼: LayoutAnimationController

XML之中指定ViewGrouplayoutAnimation屬性便可生效

Activity切換效果

使用overridePendingTransiton(int start,int exit),分別傳入動畫的id,在startActivity(intent)finish()方法後生效

使用動畫應該注意的

  • 避免使用幀動畫(AnimationDrawable

    防止圖片過大、過多出現OOM的狀況

  • 防止內存泄漏:Activity退出關閉時關閉無限循環的動畫

  • 使用view動畫後若要作可見性操做請先clearAAnimation()清除

  • 儘可能使用dp而不是px

  • 元素交互:

    在3.0後,屬性動畫的單擊事件觸發位置爲移動後的位置,可是view動畫仍是在原來的位置

  • 建議開啓硬件加速

    提升動畫流暢性

附錄:效果圖

AccelerateDecelerateInterpolator
AccelerateInterpolator
AnticipateInterpolator
AnticipateOvershootInterpolator
BounceInterpolator
CycleInterpolator
DecelerateInterpolator
LinearInterpolator
OvershootInterpolator

點我回城

相關文章
相關標籤/搜索