Android 動畫


該文章是一個系列文章,是本人在Android開發的漫漫長途上的一點感想和記錄,我會盡可能按照先易後難的順序進行編寫該系列。該系列引用了《Android開發藝術探索》以及《深刻理解Android 卷Ⅰ,Ⅱ,Ⅲ》中的相關知識,另外也借鑑了其餘的優質博客,在此向各位大神表示感謝,膜拜!!!android


前言

該篇博客咱們來講說Android動畫的那些事。app

Android動畫簡介

Android的動畫是一個使人着迷的地方,不過Android的動畫能夠簡單分爲3類,View動畫,屬性動畫。下面咱們分別介紹。dom

View動畫

 View動畫顧名思義其做用對象爲View,包含平移、縮放、旋轉、透明,這四類變化分別對應着Animation的子類TranlateAnimation、ScaleAnimation、RotateAnimation和AlphaAnimation。雖然有對應的類,不過,在Android動畫中,仍是建議用XML來定義,其對應的標籤以下所示
ide

View動畫的XML描述語法的固定格式函數

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@[package:]anim/interpolator_resource"
android:shareInterpolator=["true"|"false"]>
    <translate
        android:fromXDelta="float"
        android:fromYDelta="float"
        android:toXDelta="float"
        android:toYDelta="-float"
        android:duration="float"
        />
    <scale
        android:fromXScale="float"
        android:fromYScale="float"
        android:toXScale="float"
        android:toYScale="float"
        android:pivotX="float"
        android:pivotY="float"
        android:duration="float"
        />
    <rotate
        android:fromDegrees="float"
        android:toDegrees="float"
        android:pivotX="float"
        android:pivotY="float"
        android:duration="float"
        />
    <alpha 
        android:fromAlpha="float"
        android:toAlpha="float"
        android:duration="float"
        />
    ...
</set>

注:
android:interpolator表示動畫集合所採用的插值器,插值器影響動畫的速度,默認是@android:anim/accelerate_decelerate_interpolator,即加減速插值器,關於插值器的概念將會在下面介紹
android:shareInterpolator表示集合中的動畫和集合共享同一個插值器,若是集合不指定插值器,那麼子動畫就須要單獨指定插值器或者使用默認值。動畫

View動畫座標系

在使用View動畫時,就不得不提View的動畫座標體系,以下圖,其座標系是以View的左上角爲原點,橫向向右爲x軸正方向,縱向向下爲y軸正方向,在平移中toXDelta爲正數表示以原點爲參考沿x軸向右移動,爲負數時,反之,旋轉時正數角度表示順時針this

View動畫的主體是View,更準確的說是View的副本(影子),View動畫更改的只是顯示,其x,y座標仍然沒有改變,響應事件的位置沒有改變,也就是說view自己並無改變。lua

也所以,不要使用View動畫作交互性操做,例如點擊。如今View動畫已經不多人使用了,不過View動畫簡單已用,能夠用來作一些簡單的不須要交互的動畫。spa

View動畫屬性配置中 %以及%p的含義

咱們先來看一段代碼翻譯

<translate 
   ...
   android:fromXDelta="0.0"
   android:toXDelta="50.0%p"
   android:fromYDelta="0.0"
   android:toYDelta="-50.0%p" />

 <scale
    ...
    android:pivotX="50.0%"
    android:pivotY="100.0%"/>
  1. android:fromXDelta="X",X>0 表示以View動畫的開始位置是以當前View的原點向右偏移X個位置,同理,X<0時View動畫的開始位置是以當前View的原點向左偏移X個位置
  2. android:fromXDelta="X%",X>0 表示以View動畫的開始位置是以當前View的原點向右偏移View寬度的X%(View.width*X%)個位置,同理,X<0時View動畫的開始位置是以當前View的原點向左偏移向右偏移View寬度的X%(View.width*X%)個位置
  3. android:fromXDelta="X%p",X>0 表示以View動畫的開始位置是以當前View的父View的原點向右偏移父View寬度的X%(View.Parent.width*X%)個位置,同理,X<0時View動畫的開始位置是以當前View的父View的原點向左偏移向右偏移父View寬度的X%(View.Parent.width*X%)個位置

自定義View動畫

自定義View動畫既簡單又複雜,簡單的是一個新的動畫類只需繼承Animation類並重寫2個方法,代碼以下所示

public class CustomAnimation extends Animation {
    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        super.applyTransformation(interpolatedTime, t);
    }
}

說他複雜呢,是由於View動畫的過程其實是矩陣變換的過程,這個涉及線性代數的知識。

View動畫的特殊應用場景

LayoutAnimation

LayoutAnimation用於ViewGroup,爲ViewGroup指定一個動畫,這樣它的全部子View在出場時都帶有指定的動畫效果。

<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
    android:animation="@anim/bm_anim_bottom_in"
    android:animationOrder="normal"
    android:delay="0.5" />

android:animation,爲子元素指定具體的入場動畫,本例中的代碼以下

<set xmlns:android="http://schemas.android.com/apk/res/android"
  android:duration="500">
  <translate
      android:fromYDelta="50.0%p"
      android:interpolator="@android:anim/accelerate_decelerate_interpolator"
      android:toYDelta="0.0" />
  <alpha
      android:fromAlpha="0.0"
      android:interpolator="@android:anim/accelerate_decelerate_interpolator"
      android:toAlpha="1.0" />
</set>

android:delay,表示子元素開始動畫的延遲,好比子元素的入場時間週期爲500ms,那麼0.5 表示每一個子元素都要延遲500*0.5=250ms後纔會開始播放。整體來講就是第一個子元素延遲250ms播放,第二個子元素延遲500ms播放,後面的子元素以此類推。
android:animationOrder,表示子元素動畫的順序,有三種選項:normal,reverse,random,其中normal表示順序顯示,即排在前面的子元素先開始播放入場動畫;reverse表示逆向顯示,即排在後面的子元素先開始播放入場動畫;random則表示隨機播放入場動畫。

LayoutAnimation的使用

LayoutAnimation的使用比較簡單,可直接在ViewGroup內指定android:layoutAnimation屬性,以下所屬

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/view_group"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layoutAnimation="@anim/bm_layout_anim_item_bottom_in"
    android:orientation="vertical">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="1!"
        android:textSize="20sp" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="2!"
        android:textSize="20sp" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="3!"
        android:textSize="20sp" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="4!"
        android:textSize="20sp" />


</LinearLayout>

也可使用代碼控制,以下所示

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //使用AnimationUtils類的靜態方法loadAnimation()來加載XML中的動畫XML文件
        Animation animation = AnimationUtils.loadAnimation(this, R.anim.bm_anim_bottom_in);
        ViewGroup viewGroup = findViewById(R.id.view_group);
        LayoutAnimationController layoutAnimationController = new LayoutAnimationController(animation);
        layoutAnimationController.setDelay(0.5f);
        layoutAnimationController.setOrder(LayoutAnimationController.ORDER_NORMAL);
        viewGroup.setLayoutAnimation(layoutAnimationController);
    }
}

Activity之間的切換動畫

Activity有本身的默認切換效果,不過咱們也能本身定義Activity的切換效果,主要用到類Activity的一個函數overridePendingTransition(int enterAnim, int exitAnim),參數說明以下

  • enterAnim:表示Activity被打開時所須要的動畫資源id
  • exitAnim:表示Activity被暫停時所須要的動畫資源id

啓動一個Activity時,可按照下面的代碼爲其添加切換效果

startActivity(new Intent(this,Main2Activity.class));
overridePendingTransition(R.anim.pop_enter_anim,R.anim.pop_exit_anim);

@Override
public void finish() {
    super.finish();
    overridePendingTransition(R.anim.pop_enter_anim,R.anim.pop_exit_anim);
}

須要注意的是overridePendingTransition必須放在startActivity或者finish以後,纔有動畫效果

插值器與估值器

  TimeInterpolator中文翻譯爲時間插值器,它的做用是根據時間流逝的百分比來計算出當前屬性值改變的百分比。系統預置的有LinearInterpolator(線性插值器:勻速動畫)、AccelerateDecelerateInterpolator(加速減速插值器:動畫兩頭慢中間快)和DecelerateInterpolator(減速插值器:動畫愈來愈慢),OvershootInterpolator(抖動動畫)等。

  TypeEvaluator,估值器,它的做用是根據當前屬性改變的百分比來計算改變後的屬性值。系統預置的有IntEvaluator(針對整型屬性)和FloatEvaluator(針對浮點型屬性),ArgbEvaluator(針對Color屬性)
  

View動畫的實際實現者Matrix

前面也說過View動畫的過程其實是矩陣變換的過程,Matrix就是操做矩陣變換的類。Matrix是一個3*3的矩陣,默認建立一個Matrix的對象的時候該矩陣是一個單位矩陣。

if (mMatrix == null) {
   mMatrix = new Matrix();//新建對象時默認矩陣是一個3*3的單位矩陣
} else {
   mMatrix.reset();//reset方法將該矩陣重置爲一個3*3的單位矩陣
}

默認的單位矩陣以下圖,
這裏寫圖片描述

那麼這個單位矩陣表示什麼意思呢,咱們再來看下圖。
這裏寫圖片描述
上面的數值與下面的屬性一一對應,
MSCALE_X|Y對應的是縮放變化,
MTRANS_X|Y對應的是平移變化,
MSKEW_X|Y對應的是錯切變化

下面我以平移動畫爲例說明該矩陣如何做用於動畫的。咱們假設當前View的原點座標爲,那麼咱們想讓該View的原點橫向移動,縱向移動

那麼用矩陣表示該過程是
這個行列式前面表示變換的矩陣即Matrix,後面的矩陣是咱們View的座標矩陣,也就是說View平移動畫的過程是把座標矩陣點乘一個變換矩陣獲得最後的結果矩陣。其餘的變化與平移變換相似,更改Matrix矩陣中相關份量便可。


本篇總結

本篇呢,對Android的View動畫作了一個比較深刻的講解以及分析,有不到之處還請指出。


下篇預告

下篇呢,繼續對Android動畫的另一個大類屬性動畫做分析


此致,敬禮

相關文章
相關標籤/搜索