淺析Android動畫(一),View動畫高級實例探究

轉載請註明出處!http://www.cnblogs.com/wondertwo/p/5295976.htmlhtml


視圖動畫的基本用法

提起 Android 動畫不少初學者就會一臉懵逼二階茫然,當初翻遍圖書館的一大堆入門書籍都找不到一本書在講 Android 動畫機制,好在一顆癡迷技術的心讓我自備燃料善始善終,最後總算弄明白了 Android 動畫究竟是個什麼鬼。其實咱們有木有常常用手機拍了不少漂亮照片之後,打開相冊,點擊更多,點擊自動播放,這些靜態的照片就會連貫的播放起來了有木有?這其實就是逐幀動畫,相似於動畫片的效果。是否是很簡單呢?關於Android動畫的分類我查了不少資料,最初只有兩種動畫即逐幀動畫(frame-by-frame animation)和補間動畫(tweened animation),補間動畫只須要開發者設置動畫的起始值和結束值,中間的動畫由系統自動幫咱們完成,下面要介紹的視圖動畫就屬於補間動畫。可是從Android 3.x開始谷歌引入了一種全新的動畫——屬性動畫,相對於視圖動畫只能給View對象設置動畫效果來講,屬性動畫要強大的太多,只要是一個Object對象屬性動畫都能爲其設置動畫屬性,無論這個對象能不能看得見,會不會與用戶產生交互。關於屬性動畫的用法會在下一篇博客中詳細介紹,下面的主要以講解視圖動畫爲主。視圖動畫即咱們常說的 View Animation, 有四種效果以下:android

  • 透明度變化(AlphaAnimation);
  • 位移(TranslateAnimation);
  • 縮放(ScaleAnimation);
  • 旋轉(RotateAnimation);

能夠從Android api文檔看到視圖動畫 Add in api level 1 ,算是 Android 動畫家族中的老臘肉了。那咱們就從視圖動畫的基本用法着手,一步步深刻學習!這裏先放上狂炫酷帥的QQ客戶端抖一抖動畫和3D旋轉&電視關閉畫面的自定義動畫,哈哈,這都是用視圖動畫作出來的效果哦!api

QQ抖一抖

電視關機畫面&3D旋轉

哈哈,上面的自定義動畫有木有驚豔到你呢?「每個宅男心中都藏着一個女神」,你看的沒錯!畫面中就是個人女神——張鈞甯。上面的動畫特效是在四種最基本的視圖動畫的基礎上稍加改進出來的,那麼四種基本的視圖動畫效果如何呢?app

AlphaAnimation

ScaleAnimation

RotateAnimation

TranslateAnimation

分別對應着透明度變化(AlphaAnimation),縮放(ScaleAnimation),旋轉(RotateAnimation),位移(TranslateAnimation); View 動畫的四種變換效果對應着的 AlphaAnimation , ScaleAnimation , RotateAnimation , TranslateAnimation 這4個動畫類都繼承自 Animation 類,Animation 類是全部視圖動畫類的父類,後面講解的自定義動畫類其實也必須繼承 Animationide

而且既能夠在代碼中動態的指定這四種動畫效果,也能夠在 xml 文件中定義, xml 文件中視圖動畫的目錄是 res/anim/file_name.xml ,與視圖動畫不一樣, xml 文件中屬性動畫的目錄是 res/animator/file_name.xml ,不過屬性動畫並不推薦在 xml 文件中定義,關於屬性動畫請關注個人下一篇博客哦 。xml 文件中視圖動畫代碼以下,透明度動畫對應標籤 <alpha> ,縮放動畫對應標籤 <scale> ,旋轉動畫對應標籤 <rotate> ,位移動畫對應標籤 <translate> ,根標籤 <set> 就表示一個動畫集合 AnimationSetshareInterpolator="true" 表示動畫集合中的全部動畫共享插值器,反之shareInterpolator="false" 表示不共享插值器,關於插值器會在第二篇博客的屬性動畫中詳細介紹。函數

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="true" >

    <!--透明度-->
    <alpha
        android:fromAlpha="0"
        android:toAlpha="1" />

    <!--縮放-->
    <scale
        android:fromXScale="0.5f"
        android:fromYScale="1.5f"
        android:toXScale="0.5f"
        android:toYScale="1.5f"
        android:pivotX="100"
        android:pivotY="100" />

    <!--位移-->
    <translate
        android:fromXDelta="0"
        android:toXDelta="0"
        android:fromYDelta="200"
        android:toYDelta="200" />

    <!--旋轉-->
    <rotate
        android:fromDegrees="0"
        android:toDegrees="360"
        android:pivotX="200"
        android:pivotY="200" />

</set>

以上代碼標籤中的屬性值,其具體含義以下:post

  • alpha
    • fromAlpha ---- 透明度起始值,0表示徹底透明
    • toAlpha ---- 透明度最終值,1表示不透明
  • scale
    • fromXScale ---- 水平方向縮放的起始值,好比0
    • fromYScale ---- 豎直方向縮放的起始值,好比0
    • toXScale ---- 水平方向縮放的結束值,好比2
    • toYScale ---- 豎直方向縮放的結束值,好比2
    • pivotX ---- 縮放支點的x座標
    • pivotY ---- 縮放支點的y座標(支點能夠理解爲縮放的中心點,縮放過程當中這點的座標是不變的;支點默認在中心位置)
  • translate
    • fromXDelta ---- x起始值
    • toXDelta ---- x結束值
    • fromYDelta ---- y起始值
    • toYDelta ---- y結束值
  • rotate
    • fromDegrees ---- 旋轉起始角度
    • toDegrees ---- 旋轉結束角度

除此以外,還有一些常見的屬性值,以下:學習

  • android:duration ---- 動畫的持續時間
  • android:fillAfter ---- true表示保持動畫結束時的狀態,false表示不保持

上面就是經過 xml 文件定義的 View 動畫,那怎麼應用上面的動畫呢?也很簡單,經過 View 對象在代碼中動態加載便可,代碼以下。值得注意的是,AnimationUtils.loadAnimation(this, R.anim.ani_view) 方法接收兩個參數,第一個是當前的上下文環境,第二個就是咱們經過 xml 定義的動畫啦。代碼以下:測試

ImageView ivAni = (ImageView) findViewById(R.id.iv_ani);
Animation ani = AnimationUtils.loadAnimation(this, R.anim.ani_view);
ivAni.startAnimation(ani);

OK那麼問題來了,怎樣直接經過代碼動態定義 View 動畫呢?也很簡單,先上代碼以下:動畫

AlphaAni----透明度動畫代碼以下,相信你通過前面的部分已經能很容易就看懂這些代碼了,在 beginAnimation() 方法中,咱們在3000ms的時間內把一個 LinearLayout 對象 llAlpha 的透明度從0到1,即從徹底透明漸變到徹底不透明,而後在 onCreate() 方法中調用 beginAnimation() 方法就能以透明度漸變更畫的方式跳轉到 AlphaAni :

package com.wondertwo.viewani;

import android.app.Activity;
import android.os.Bundle;
import android.view.animation.AlphaAnimation;
import android.widget.LinearLayout;

import com.wondertwo.R;

/**
 * AlphaAni----透明度動畫
 * Created by wondertwo on 2016/3/11.
 */
public class AlphaAni extends Activity {

    private LinearLayout llAlpha;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_alpha);
        llAlpha = (LinearLayout) findViewById(R.id.ll_alpha);
        beginAnimation();
    }

    // 啓動動畫
    private void beginAnimation() {
        AlphaAnimation alpha = new AlphaAnimation(0, 1);// 0---->1從透明到不透明
        alpha.setDuration(3000);// 設置動畫持續時間
        llAlpha.startAnimation(alpha);// 啓動動畫
    }
}

ScaleAni----縮放動畫代碼以下,與上面的透明度漸變更畫相似,經過 ctrl+左鍵 查看源碼能夠知道,在建立 ScaleAnimation 縮放動畫的對象的時候, ScaleAnimation(0, 2, 0, 2) 接受的四個參數分別是 ScaleAnimation(float fromX, float toX, float fromY, float toY)

package com.wondertwo.viewani;

import android.app.Activity;
import android.os.Bundle;
import android.view.animation.ScaleAnimation;
import android.widget.LinearLayout;

import com.wondertwo.R;

/**
 * ScaleAni----縮放動畫
 * Created by wondertwo on 2016/3/11.
 */
public class ScaleAni extends Activity {

    private LinearLayout llScale;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scale);
        llScale = (LinearLayout) findViewById(R.id.ll_scale);
        beginAnimation();
    }

    // 啓動動畫
    private void beginAnimation() {
        ScaleAnimation scale = new ScaleAnimation(0, 2, 0, 2);
        scale.setDuration(3000);
        llScale.startAnimation(scale);
    }
}

RotateAni----旋轉動畫代碼以下,表示把一個 View 對象從起始角度0旋轉到360度,後面的四個參數 RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f 表示以中心位置爲旋轉支點:

package com.wondertwo.viewani;

import android.app.Activity;
import android.os.Bundle;
import android.view.animation.RotateAnimation;
import android.widget.LinearLayout;

import com.wondertwo.R;

/**
 * RotateAni----旋轉動畫
 * Created by wondertwo on 2016/3/11.
 */
public class RotateAni extends Activity {

    private LinearLayout llRotate;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_rotate);
        llRotate = (LinearLayout) findViewById(R.id.ll_rotate);
        beginAnimation();
    }

    // 啓動動畫
    private void beginAnimation() {
        RotateAnimation rotate = new RotateAnimation(0, 360,
                RotateAnimation.RELATIVE_TO_SELF, 0.5f,
                RotateAnimation.RELATIVE_TO_SELF, 0.5f);
        rotate.setDuration(3000);
        llRotate.startAnimation(rotate);
    }
}

TranslateAni----位移動畫代碼以下,表示把 View 對象從起始座標 (0, 0) 位移到 (200, 300) ,是否是很簡單呢:

package com.wondertwo.viewani;

import android.app.Activity;
import android.os.Bundle;
import android.view.animation.TranslateAnimation;
import android.widget.LinearLayout;

import com.wondertwo.R;

/**
 * TranslateAni----位移動畫
 * Created by wondertwo on 2016/3/11.
 */
public class TranslateAni extends Activity {

    private LinearLayout llTranslate;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_translate);
        llTranslate = (LinearLayout) findViewById(R.id.ll_translate);
        beginAnimation();
    }

    // 啓動動畫
    private void beginAnimation() {
        TranslateAnimation translate = new TranslateAnimation(0, 200, 0, 300);
        translate.setDuration(3000);
        llTranslate.startAnimation(translate);
    }
}

視圖動畫的高級用法

趁熱打鐵,接下來正是掌握 View 動畫高級用法的好時機啦,所謂高級用法,其實也很簡單,就是把上面的四種基本效果進行任意的排列組合,而後設定重複次數、重複模式(經常使用的重複模式有順序、逆向等等),同時啓動或者延遲必定的時間啓動動畫!爲了更直觀感覺視圖動畫的高級用法,直接上圖請往下看,一種很酷炫的圖片旋轉飛入效果!

四種基本效果的組合動畫

直接上代碼以下,看過代碼確定會以爲,不就是把上面介紹的四種動畫組合到一塊兒了嘛,事實上就是這麼簡單。

package com.wondertwo.viewani;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.RotateAnimation;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.LinearLayout;

import com.wondertwo.MainActivity;
import com.wondertwo.R;

/**
 * AlphaAnimation、RotateAnimation、ScaleAnimation、TranslateAnimation四種視圖動畫的組合動畫
 * Created by wondertwo on 2016/3/11.
 */
public class GroupAni extends Activity {

    private LinearLayout llGroup;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_group);
        llGroup = (LinearLayout) findViewById(R.id.ll_group);
        beginAnimation();
    }

    // 啓動組合動畫
    private void beginAnimation() {
        // 建立動畫集合
        AnimationSet aniSet = new AnimationSet(false);

        // 透明度動畫
        AlphaAnimation alpha = new AlphaAnimation(0, 1);
        alpha.setDuration(4000);
        aniSet.addAnimation(alpha);

        // 旋轉動畫
        RotateAnimation rotate = new RotateAnimation(0, 360,
                RotateAnimation.RELATIVE_TO_SELF, 0.5f,
                RotateAnimation.RELATIVE_TO_SELF, 0.5f);
        rotate.setDuration(4000);
        aniSet.addAnimation(rotate);

        // 縮放動畫
        ScaleAnimation scale = new ScaleAnimation(1.5f, 0.5f, 1.5f, 0.5f);
        scale.setDuration(4000);
        aniSet.addAnimation(scale);

        // 位移動畫
        TranslateAnimation translate = new TranslateAnimation(0, 160, 0, 240);
        translate.setDuration(4000);
        aniSet.addAnimation(translate);

        // 動畫監聽
        aniSet.setAnimationListener(new Animation.AnimationListener() {
            // 動畫開始
            @Override
            public void onAnimationStart(Animation animation) {

            }

            // 動畫結束,通常在這裏實現頁面跳轉邏輯
            @Override
            public void onAnimationEnd(Animation animation) {
                // 動畫結束後,跳轉到主頁面
                startActivity(new Intent(GroupAni.this, MainActivity.class));
            }

            // 動畫重複
            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });

        // 把動畫設置給llGroup
        llGroup.startAnimation(aniSet);
    }
}

惟一不一樣的是,咱們此次是把四個 View 動畫裝進了一個動畫集合(AnimationSet)中,至於動畫集合,你就把他當作普通的 Set 集合使用就好,建立動畫集合時傳入的參數 false 表示動畫集合中裝入的和四個 View 動畫不共享插值器。到這裏你已經學會 View 動畫了,可是後面還有更高級用法呢!


自定義View動畫

當你看完上面的 View 動畫,自定義 View 動畫對你來講已經不在話下,我準備的兩個 demo 你確定很期待,分別是:模仿QQ客戶端的抖一抖特效,和電視畫面關閉&3D旋轉,效果以下:

QQ抖一抖

模仿QQ客戶端的抖一抖特效,先上代碼!

package com.wondertwo.qqTremble;

import android.view.animation.Animation;
import android.view.animation.Transformation;

/**
 * QQ抖一抖特效的自定義View動畫實現
 * Created by wondertwo on 2016/3/17.
 */
public class QQTrembleAni extends Animation {
    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        t.getMatrix().setTranslate(
                (float) Math.sin(interpolatedTime * 50) * 8,
                (float) Math.sin(interpolatedTime * 50) * 8
                );// 50越大頻率越高,8越小振幅越小
        super.applyTransformation(interpolatedTime, t);
    }
}

上面這段代碼就是咱們自定義的QQ抖一抖動畫了,全部的自定義動畫都須要繼承 android.view.animation.Animation 抽象類,而後重寫 initialize()applyTransformation() 這兩個方法,在 initialize() 方法中對一些變量進行初始化,在 applyTransformation() 方法中經過矩陣修改動畫數值,從而控制動畫的實現過程,這也是自定義動畫的核心。 applyTransformation(float interpolatedTime, Transformation t) 方法在動畫的執行過程當中會不斷地調用,能夠看到接收的兩個參數分別是 float interpolatedTime 表示當前動畫進行的時間與動畫總時間(通常在 setDuration() 方法中設置)的比值,從0逐漸增大到1; Transformation t 傳遞當前動畫對象,通常能夠經過代碼 android.graphics.Matrix matrix = t.getMatrix() 得到 Matrix 矩陣對象,再設置 Matrix 對象,通常要用到 interpolatedTime 參數,以此達到控制動畫實現的結果。能夠看到在上面的代碼中 t.getMatrix().setTranslate((float) Math.sin(interpolatedTime * 50) * 8, (float) Math.sin(interpolatedTime * 50) * 8) 設置了 Matrix 對象的 Translate ,傳入的參數是一個正弦函數值,這個值是經過 interpolatedTime 參數計算出來的,這樣就實現了動畫在x,y軸兩個方向上的來回抖動效果。

下面是QQ抖一抖動畫的測試類 Activity ,代碼以下:

package com.wondertwo.qqTremble;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.RelativeLayout;

import com.wondertwo.R;

/**
 * 模仿QQ抖一抖效果的測試類
 * Created by wondertwo on 2016/3/17.
 */
public class QQTrembleTest extends Activity {

    private RelativeLayout rlTremble;
    private Button btnTremble;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_qq_tremble);
        rlTremble = (RelativeLayout) findViewById(R.id.rl_tremble);
        btnTremble = (Button) findViewById(R.id.btn_tremble);

        // 建立抖一抖動畫對象
        final QQTrembleAni tremble = new QQTrembleAni();
        tremble.setDuration(800);// 持續時間800ms,持續時間越短頻率越高
        tremble.setRepeatCount(2);// 重複次數,不包含第一次

        // 設置按鈕點擊監聽
        btnTremble.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // 啓動抖一抖效果
                rlTremble.startAnimation(tremble);
            }
        });
    }
}

接着咱們再看一個酷炫的自定義動畫,相似電視機關機畫面和圖片3D旋轉,效果以下!

電視關機畫面&3D旋轉

直接上代碼,電視關機畫面效果動畫 TVCloseAni 以下:

package com.wondertwo.custom;

import android.graphics.Matrix;
import android.view.animation.Animation;
import android.view.animation.Transformation;

/**
 * 經過矩陣變換模擬電視關閉效果,使圖片的縱向比例不斷縮小
 * Created by wondertwo on 2016/3/13.
 */
public class TVCloseAni extends Animation {

    private int mCenterWidth, mCenterHeight;

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        // 設置默認時長
        setDuration(4000);
        // 保持動畫的結束狀態
        setFillAfter(true);
        // 設置默認插值器
        // setInterpolator(new BounceInterpolator());// 回彈效果的插值器
        mCenterWidth = width / 2;
        mCenterHeight = height /2;
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        super.applyTransformation(interpolatedTime, t);
        final Matrix matrix = t.getMatrix();
        matrix.preScale(1,
                        1 - interpolatedTime,
                        mCenterWidth,
                        mCenterHeight);
    }
}

圖片3D旋轉效果動畫代碼以下:

package com.wondertwo.custom;

import android.graphics.Camera;
import android.graphics.Matrix;
import android.view.animation.Animation;
import android.view.animation.BounceInterpolator;
import android.view.animation.Transformation;

/**
 *
 * Created by wondertwo on 2016/3/13.
 */
public class CustomAni extends Animation {

    private int mCenterWidth, mCenterHeight;
    private Camera mCamera = new Camera();
    private float mRotateY = 0.0f;

    // 通常在此方法初始化一些動畫相關的變量和值
    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
        super.initialize(width, height, parentWidth, parentHeight);
        // 設置默認時長
        setDuration(4000);
        // 保持動畫的結束狀態
        setFillAfter(true);
        // 設置默認插值器
        setInterpolator(new BounceInterpolator());// 回彈效果的插值器
        mCenterWidth = width / 2;
        mCenterHeight = height /2;
    }

    // 暴露接口設置旋轉角度
    public void setRotateY(float rotateY) {
        mRotateY = rotateY;
    }

    // 自定義動畫的核心,在動畫的執行過程當中會不斷回調此方法,而且每次回調interpolatedTime值都在不斷變化(0----1)
    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
        super.applyTransformation(interpolatedTime, t);
        final Matrix matrix = t.getMatrix();
        mCamera.save();
        // 使用Camera設置Y軸方向的旋轉角度
        mCamera.rotateY(mRotateY * interpolatedTime);
        // 將旋轉變化做用到matrix上
        mCamera.getMatrix(matrix);
        mCamera.restore();
        // 經過pre方法設置矩陣做用前的偏移量來改變旋轉中心
        matrix.preTranslate(mCenterWidth, mCenterHeight);// 在旋轉以前開始位移動畫
        matrix.postTranslate(-mCenterWidth, -mCenterHeight);// 在旋轉以後開始位移動畫
    }
}

下面是電視機關機畫面和圖片3D旋轉動畫的測試類, CustomAniTest 代碼以下!

package com.wondertwo.custom;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;

import com.wondertwo.R;

/**
 * 自定義動畫測試類
 * Created by wondertwo on 2016/3/13.
 */
public class CustomAniTest extends Activity {

    private boolean flag = true;// 標記位,輪換展現兩種自定義動畫

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_custom_ani);
    }

    /**
     * 設置按鈕點擊事件
     */
    public void startCustomAni(View view) {
        if (flag) {
            TVCloseAni tvAni = new TVCloseAni();
            view.startAnimation(tvAni);
            // 重置標記位
            flag = false;
        } else {
            CustomAni customAni = new CustomAni();
            customAni.setRotateY(30);
            view.startAnimation(customAni);
            // 重置標記位
            flag = true;
        }
    }
}

惟一不一樣的是在上面3D旋轉自定義動畫中,咱們引入了 Camera 的概念, android.graphics.Camera 中的 Camera 類封裝了 openGL 的3D動畫,所以能夠經過 Camera 類實現不少酷炫的3D動畫效果。關於Android中矩陣Matrix的概念,在不少地方都會用到,好比圖片處理,動畫變換等等地方,這裏我就不仔細展開啦!貼上http://www.cnblogs.com/qiengo/archive/2012/06/30/2570874.html#code,看完你確定能明白矩陣的巨大威力啦,這裏感謝原做者!


在最後附上淺析Android動畫系列的三篇文章:

  1. 淺析Android動畫(一),View動畫高級實例探究 http://www.cnblogs.com/wondertwo/p/5295976.html
  2. 淺析Android動畫(二),屬性動畫與高級實例探究 http://www.cnblogs.com/wondertwo/p/5312482.html
  3. 淺析Android動畫(三),自定義Interpolator與TypeEvaluator http://www.cnblogs.com/wondertwo/p/5327586.html

若是以爲不錯,請繼續關注哦!下一篇將繼續介紹Android屬性動畫哈!

相關文章
相關標籤/搜索