1. 程式人生 > >Android三大動畫介紹及使用

Android三大動畫介紹及使用

前言:
動畫在安卓開發中的使用非常普遍,基本上任何帶有動效的轉換都是基於動畫實現的。那麼接下來我們就來了解一下安卓中的幾大動畫。

動畫的分類:
安卓中把動畫分為三大類:幀動畫、補間動畫、屬性動畫。而嚴格意義上來說這三種動畫其實就是Android3.0之前的傳統動畫和3.0之後的屬性動畫,傳統動畫又分為幀動畫和補間動畫。

1.幀動畫:
幀動畫要說是三種動畫中比較簡單的一種了,它是基於一連串的圖片完成的,它的原理就是將一張張單獨的圖片進行連續播放,從而在視覺上產生一種動畫的效果;有點類似於某些軟體製作gif動畫的方式。
這裡寫圖片描述
上圖中的動畫就是通過幀動畫播放一連貫的圖片實現的視覺上的動效,附上drawable的XML和java程式碼:

<?xml version="1.0" encoding="utf-8"?>
<!--
android:oneshot="true" 表示幀動畫是否重複播放,預設為false,true表示只播放一次
-->
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
                android:oneshot="false">
    <item
        android:drawable="@drawable/p00"
        android:duration
="200"/>
<item android:drawable="@drawable/p11" android:duration="200"/> <item android:drawable="@drawable/p22" android:duration="200"/> <item android:drawable="@drawable/p33" android:duration="200"/> <item android:drawable
="@drawable/p44" android:duration="200"/>
</animation-list>

Activity程式碼:

package com.example.administrator.myapplication;

import android.graphics.drawable.AnimationDrawable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;

public class FrameActivity extends AppCompatActivity {

    private ImageView iv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_zhen);
        iv = ((ImageView) findViewById(R.id.frame_iv));
        iv.setImageResource(R.drawable.frame);
    }

    public void playFrameAnim(View view) {
        AnimationDrawable ad = (AnimationDrawable) iv.getDrawable();
        //判斷幀動畫是否正在播放
        if (ad.isRunning()) {
            //停止播放
            ad.stop();
        }else {
            //開始播放
            ad.start();
        }
    }
}

2.補間動畫:
補間動畫又可以分為四種形式:alpha(淡入淡出)、translate(位移)、scale(縮放)、rotate(旋轉)。
補間動畫的實現,一般會採用xml 檔案的形式;程式碼會更容易書寫和閱讀,同時也更容易複用(當然也是可以在java程式碼中實現)。
補間動畫作用的最小元素為View,補間動畫的執行並不會真正改變控制元件的屬性值預設情況下,補間動畫的執行速率都是先加速後減速,插值器用來控制動畫的執行速率,通過插值器可以修改動畫的執行速率

XML中實現:
首先在res/anim/ 資料夾下定義如下的動畫實現方式:

alpha_anim.xml 動畫實現

<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:fromAlpha="1.0"
    android:interpolator="@android:anim/accelerate_decelerate_interpolator"
    android:toAlpha="0.0" />

scale_anim.xml 動畫實現

<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="1000"
    android:fromXScale="0.0"
    android:fromYScale="0.0"
    android:pivotX="50%"
    android:pivotY="50%"
    android:toXScale="1.0"
    android:toYScale="1.0"/>

translate_anim.xml 動畫實現

<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="3000"
    android:fromXDelta="0"
    android:fromYDelta="0"
    android:toXDelta="200"
    android:toYDelta="200" />

rotate_anim.xml 動畫實現

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="3000"
    android:fromDegrees="0"
    android:pivotX="50%"
    android:pivotY="50%"
    android:repeatCount="infinite"
    android:repeatMode="restart"
    android:toDegrees="359"/>

也可以使用set 標籤將多個動畫進行組合

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >
    <alpha
        android:fromAlpha="float"
        android:toAlpha="float" />
    <scale
        android:fromXScale="float"
        android:toXScale="float"
        android:fromYScale="float"
        android:toYScale="float"
        android:pivotX="float"
        android:pivotY="float" />
    <translate
        android:fromXDelta="float"
        android:toXDelta="float"
        android:fromYDelta="float"
        android:toYDelta="float" />
    <rotate
        android:fromDegrees="float"
        android:toDegrees="float"
        android:pivotX="float"
        android:pivotY="float" />
    <set>
        ...
    </set>
</set>

然後在程式碼中設定給View:

Animation animation = AnimationUtils.loadAnimation(mContext, R.anim.alpha_anim);
img = (ImageView) findViewById(R.id.img);
img.startAnimation(animation);

經過以上步驟就可以給ImageView設定不同的動畫啦。

稍稍介紹:
Interpolator 主要作用是可以控制動畫的變化速率 ,就是動畫進行的快慢節奏。
pivot 決定了當前動畫執行的參考位置。
pivot 這個屬性主要是在translate 和 scale 動畫中,這兩種動畫都牽扯到view 的“物理位置“發生變化,所以需要一個參考點。而pivotX和pivotY就共同決定了這個點;它的值可以是float或者是百分比數值。

我們以pivotX為例:

pivotX取值 含義
10 距離動畫所在view自身左邊緣10畫素
10% 距離動畫所在view自身左邊緣 的距離是整個view寬度的10%
10%p 距離動畫所在view父控制元件左邊緣的距離是整個view寬度的10%

java程式碼中實現:
有時候,動畫的屬性值可能需要動態的調整,這個時候使用xml 就不合適了,需要使用java程式碼實現。不多說,直接上程式碼即可,註釋都在程式碼中的啦,小夥伴們很容易就能看懂了。

package com.example.administrator.myapplication;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
import android.view.animation.LinearInterpolator;
import android.view.animation.RotateAnimation;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;

public class BujianActivity extends AppCompatActivity {

    private ImageView iv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bujian);
        iv = ((ImageView) findViewById(R.id.iv));
    }

    /**
     * 程式碼設定透明度動畫
     * @param view
     */
    public void alphaAn(View view) {
        //引數1:當前透明度
        //引數2:變化之後的透明度
        //引數範圍為0~1,0表示完全透明,1表示完全不透明
        AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0);
        //設定動畫執行時間
        alphaAnimation.setDuration(3000);
        //動畫執行完畢時是否保留View執行完時的狀態
        alphaAnimation.setFillAfter(true);
        //延遲啟動,引數以毫秒為單位
//        alphaAnimation.setStartOffset();
        iv.startAnimation(alphaAnimation);
    }

    /**
     * 程式碼設定縮放動畫
     * @param view
     */
    public void scaleAn(View view) {
        //引數1:動畫開始時控制元件的寬度(0表示控制元件的寬度為實際寬度的0倍)
        //引數2:動畫結束時控制元件的寬度(1表示控制元件的寬度為實際寬度的1倍)
        //引數3:動畫開始時控制元件的高度(0表示控制元件的高度為實際高度的0倍)
        //引數4:動畫結束時控制元件的高度(2表示控制元件的高度為實際高度的2倍)
        //使用這種構造方式獲取的scale物件,在動畫縮放過程中,縮放參考點為左上角
//        ScaleAnimation scaleAnimation = new ScaleAnimation(0, 1, 0, 2);

        //最後兩個引數表示控制元件縮放的中心點,參考點為控制元件的左上角
//        ScaleAnimation scaleAnimation = new ScaleAnimation(0, 2, 0, 2, iv.getWidth() / 2, iv.getHeight() / 2);

        //最後四個引數表示縮放的中心點,ScaleAnimation.RELATIVE_TO_SELF表示縮放參考控制元件自身,0.5f表示中心點X軸座標為控制元件寬度的一半
        ScaleAnimation scaleAnimation = new ScaleAnimation(0, 2, 0, 2, ScaleAnimation.RELATIVE_TO_SELF, 0.5f, ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
        scaleAnimation.setDuration(3 * 1000);
        iv.startAnimation(scaleAnimation);
    }

    /**
     * 程式碼設定平移動畫
     * @param view
     */
    public void translateAn(View view) {
        //1.3引數表示平移的起始點座標
        //2.4引數表示平移的終點座標
//        TranslateAnimation translateAnimation = new TranslateAnimation(0, iv.getWidth(), 0, iv.getHeight());
        TranslateAnimation translateAnimation = new TranslateAnimation(TranslateAnimation.RELATIVE_TO_SELF, 0,
                TranslateAnimation.RELATIVE_TO_SELF, -1, TranslateAnimation.RELATIVE_TO_SELF, 0, TranslateAnimation.RELATIVE_TO_SELF, -1);
        translateAnimation.setDuration(3000);
        translateAnimation.setFillAfter(true);
        iv.startAnimation(translateAnimation);
    }

    /**
     * 程式碼設定旋轉動畫
     * @param view
     */
    public void rotateAn(View view) {
        //1.旋轉的起始度數
        //2.旋轉的結束度數
//        RotateAnimation rotateAnimation = new RotateAnimation(0, 359);
//        RotateAnimation rotateAnimation = new RotateAnimation(0, 359, iv.getWidth() / 2, iv.getHeight() / 2);
        RotateAnimation rotateAnimation = new RotateAnimation(0, 359, RotateAnimation.RELATIVE_TO_SELF,
                0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
        rotateAnimation.setDuration(3000);
        //設定旋轉重複次數,INFINITE表示旋轉次數無限迴圈
        rotateAnimation.setRepeatCount(RotateAnimation.INFINITE);
        //設定重複旋轉模式
        rotateAnimation.setRepeatMode(RotateAnimation.RESTART);
        //設定插值器,使動畫勻速執行
        rotateAnimation.setInterpolator(new LinearInterpolator());
        iv.startAnimation(rotateAnimation);
    }

    /**
     * 程式碼設定組合動畫
     * @param view
     */
    public void setTogetherAn(View view) {
        //true表示所有的動畫都使用AnimationSet提供的插值器
        AnimationSet set = new AnimationSet(true);
        RotateAnimation rotateAnimation = new RotateAnimation(0, 359, RotateAnimation.RELATIVE_TO_SELF,
                0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f);
        rotateAnimation.setDuration(3000);
        rotateAnimation.setRepeatCount(RotateAnimation.INFINITE);
        rotateAnimation.setRepeatMode(RotateAnimation.RESTART);
        rotateAnimation.setInterpolator(new LinearInterpolator());
        TranslateAnimation translateAnimation = new TranslateAnimation(TranslateAnimation.RELATIVE_TO_SELF, 0,
                TranslateAnimation.RELATIVE_TO_SELF, -1, TranslateAnimation.RELATIVE_TO_SELF, 0, TranslateAnimation.RELATIVE_TO_SELF, -1);
        //延遲3秒啟動平移動畫
        translateAnimation.setStartOffset(3000);
        translateAnimation.setDuration(3000);
        translateAnimation.setFillAfter(true);
        set.addAnimation(rotateAnimation);
        set.addAnimation(translateAnimation);
        iv.startAnimation(set);
    }
}

再附上效果圖:

好了,幀動畫和補間動畫就講這麼多啦。

3.屬性動畫:
屬性動畫,顧名思義,它是對於物件屬性的動畫,因此,所有補間動畫的內容,都可以通過屬性動畫實現。
屬性動畫所作用的屬性必須要有get/set方法才可以生效(後面會加以解釋)。

我們先用屬性動畫來實現上面的補間動畫效果:

java實現:

/**
     * 程式碼中用屬性動畫實現透明度變化
     * @param view
     */
    public void alphaProperty(View view) {
        //1.該動畫要作用的控制元件
        //2.要修改的屬性名稱
        //剩餘引數表示屬性的變化值
        ObjectAnimator alpha = ObjectAnimator.ofFloat(iv, "alpha", 1, 0.5f, 1, 0);
        alpha.setDuration(5000);
        alpha.setRepeatCount(-1);
        alpha.setRepeatMode(ObjectAnimator.REVERSE);
        alpha.start();
    }

    /**
     * 程式碼中用屬性動畫實現縮放變化
     * @param view
     */
    public void scaleProperty(View view) {
//        ObjectAnimator scale = ObjectAnimator.ofFloat(iv, "scaleX", 0, 1, 0, 2);
        ObjectAnimator scale = ObjectAnimator.ofFloat(iv, "scaleY", 0, 1, 0, 2);
        scale.setDuration(5000);
        scale.start();
    }

    /**
     * 程式碼中用屬性動畫實現平移變化
     * @param view
     */
    public void translateProperty(View view) {
//        ObjectAnimator translationX = ObjectAnimator.ofFloat(iv, "translationX", 0, 200);
        ObjectAnimator translationX = ObjectAnimator.ofFloat(iv, "translationY", 0, 200);
        translationX.setDuration(3000);
        translationX.start();
    }

    /**
     * 程式碼中用屬性動畫實現旋轉變化
     * @param view
     */
    public void rotateProperty(View view) {
//        ObjectAnimator rotation = ObjectAnimator.ofFloat(iv, "rotation", 0, 359);
//        ObjectAnimator rotation = ObjectAnimator.ofFloat(iv, "rotationX", 0, 359);
        ObjectAnimator rotation = ObjectAnimator.ofFloat(iv, "rotationY", 0, 359);
        rotation.setDuration(3000);
        rotation.start();
    }

    /**
     * 程式碼中用屬性動畫實現組合動畫
     * @param view
     */
    public void togetherProperty(View view) {
        ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(myView, "alpha", 1.0f, 0.5f, 0.8f, 1.0f);
        ObjectAnimator scaleXAnim = ObjectAnimator.ofFloat(myView, "scaleX", 0.0f, 1.0f);
        ObjectAnimator scaleYAnim = ObjectAnimator.ofFloat(myView, "scaleY", 0.0f, 2.0f);
        ObjectAnimator rotateAnim = ObjectAnimator.ofFloat(myView, "rotation", 0, 360);
        ObjectAnimator transXAnim = ObjectAnimator.ofFloat(myView, "translationX", 100, 400);
        ObjectAnimator transYAnim = ObjectAnimator.ofFloat(myView, "tranlsationY", 100, 750);
        AnimatorSet set = new AnimatorSet();
        set.playTogether(alphaAnim, scaleXAnim, scaleYAnim, rotateAnim, transXAnim, transYAnim);
//                set.playSequentially(alphaAnim, scaleXAnim, scaleYAnim, rotateAnim, transXAnim, transYAnim);
        set.setDuration(3000);
        set.start();
    }

XML實現:
首先,在res/animator/ 資料夾下定義如下的動畫實現方式:

translation.xml 動畫實現(平移)

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
                android:duration="3000"
                android:propertyName="translationY"
                android:valueFrom="0"
                android:valueTo="300"
                android:valueType="floatType">
</objectAnimator>

set.xml 動畫實現(組合動畫)

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <objectAnimator
        android:duration="3000"
        android:propertyName="translationY"
        android:valueFrom="0"
        android:valueTo="300"
        android:valueType="floatType">
    </objectAnimator>

    <objectAnimator
        android:duration="3000"
        android:propertyName="rotation"
        android:valueFrom="0"
        android:valueTo="359"
        android:valueType="floatType"/>
</set>

然後我們在java程式碼中做如下設定即可:

    /**
     * XML中用屬性動畫實現平移動畫
     * @param view
     */
    public void xmlAnim(View view) {
        Animator animator = AnimatorInflater.loadAnimator(this, R.animator.translation);
        //動畫作用的控制元件
        animator.setTarget(iv);
        animator.start();
    }
    /**
     * XML中用屬性動畫實現組合動畫
     * @param view
     */
    public void xmlAnim2(View view) {
        Animator animator = AnimatorInflater.loadAnimator(this, R.animator.set);
        //動畫作用的控制元件
        animator.setTarget(iv);
        animator.start();
    }

接下來我們看看自定義的屬性動畫,前面我們提到過屬性動畫作用的屬性必須要有get/set方法才有作用。比如現在我們想要自定義一個屬性動畫來實現imageview的寬度長短的變化。系統沒有為我們提供這類動畫,所以我們就得自己定義一個width屬性,然後結合ObjectAnimator實現寬度變化的動畫效果,上程式碼:

先建立一個java物件,裡面有一個width屬性:

package com.example.administrator.myapplication;

import android.view.ViewGroup;
import android.widget.ImageView;

/**
 * Created by Administrator on 2018/4/12.
 */

public class CustomPropertyModel {
    private ImageView imageView;

    /**
     * 將imageview作為引數傳進來
     * @param imageView
     */
    public CustomPropertyModel(ImageView imageView) {
        this.imageView = imageView;
    }

    public int getWidth(){
        return imageView.getLayoutParams().width;
    }

    /**
     * 修改imageview的寬度
     * @param width
     */
    public void setWidth(int width){
        ViewGroup.LayoutParams params = imageView.getLayoutParams();
        //重新設定imageview的寬度
        params.width = width;
        //重新測量寬度並顯示
        imageView.requestLayout();
    }
}

然後在Activity裡面給它設定動畫:

 /**
     * 設定寬度變化的自定義屬性動畫
     */
    public void customPropertyWidth(){
        CustomPropertyModel customPropertyModel = new CustomPropertyModel(iv);
        ObjectAnimator widthAnimation = ObjectAnimator.ofInt(customPropertyModel, "width", 100, 300);
        widthAnimation.setDuration(3000);
        widthAnimation.start();
    }

這樣就完成了一個自定義的寬度變化的動畫啦,效果如下:
這裡寫圖片描述

結語:
OK,本篇關於安卓三大動畫的基本介紹就到jie裡啦,希望小夥伴們能看懂(gif圖錄制的不是特別清晰,望各位大佬不要介意,嘿哈!)。後續我會繼續為大家帶來關於屬性動畫的文章,喜歡的話點個關注啦! 我的部落格,歡迎關注