Android動畫篇——View Animation(視圖動畫)

對於Android開發人員從初級向高級的進階過程中,動畫無疑是必不可少的一塊知識點。在合適的場景合理的使用動畫效果,可以極大的提高app的系統體驗流暢度,是優化交互和提高用戶體驗的一個重要的方面。
你可能很早就接觸過Android動畫,甚至能說出動畫分爲:View Animation、Drawable Animation和Property Animation等類型,但是你未必能詳細說出每種動畫的適用場景和不同動畫之間的差異。本文會儘可能詳盡的羅列出不同動畫的具體使用方式,適用場景,屬性設置,每種動畫的特性等知識點。關於Android動畫方面的知識將會以多篇博客的形式進行講解,本篇將針對View Animation進行說明。

OverView

You can use the view animation system to perform tweened animation on Views. Tween animation calculates the animation with information such as the start point, end point, size, rotation, and other common aspects of an animation.
A tween animation can perform a series of simple transformations (position, size, rotation, and transparency) on the contents of a View object. So, if you have a TextView object, you can move, rotate, grow, or shrink the text. If it has a background image, the background image will be transformed along with the text. The animation package provides all the classes used in a tween animation.

概要翻譯一下就是:視圖動畫可以作用在View上使之執行一系列諸如:平移、旋轉、縮放和透明度變化的補間動畫,因此視圖動畫也叫補間動畫。視圖動畫可以通過XML和Android Code兩種方式進行定義,推薦使用XML的方式來保證代碼的可讀性和可重用性。需要注意的是:視圖動畫只是修改了View在屏幕上的繪製座標和尺寸,並未改變View的真實屬性值。 比如:將一個Button通過animation移動到新的位置之後,他的點擊事件依舊會在原位置被觸發,而點擊新位置不會有任何反應。

基礎使用

先來看個GIF動畫效果,對Animation有個直觀的瞭解。
animation

Animation alphaAnimation = new AlphaAnimation(1f, 0f);
doAnimation(alphaAnimation);

/**
 * 開始動畫
 * @param animation
 */
private void doAnimation(Animation animation){
    cancelAnimation();

    //動畫監聽
    animation.setAnimationListener(new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {
            //動畫開始
            Log.d(TAG, "onAnimationStart");
        }
        @Override
        public void onAnimationEnd(Animation animation) {
            //動畫結束
            Log.d(TAG, "onAnimationEnd");
        }
        @Override
        public void onAnimationRepeat(Animation animation) {
            //動畫重複執行時觸發
            Log.d(TAG, "onAnimationRepeat");
        }
    });
    //開始動畫
    mImageView.startAnimation(animation);
}

/**
 * 清除動畫
 */
private void cancelAnimation(){
    Animation animation = mImageView.getAnimation();
    if(animation != null && animation.hasStarted() && !animation.hasEnded()){
        animation.cancel();
        mImageView.clearAnimation();
    }
}

動畫的開始、監聽和停止行爲的實現,代碼添加了詳細註釋,就不過多解釋了。

Alpha

代碼實現

//1f——100%不透明
//0f——100%透明
Animation alphaAnimation = new AlphaAnimation(1f, 0f);
alphaAnimation.setDuration(2000);       //動畫時間設置
alphaAnimation.setFillAfter(false);     //動畫結束之後是否停留在結束爲止
alphaAnimation.setFillBefore(true);     //動畫結束之後是否回到開始位置
alphaAnimation.setRepeatCount(1);       //動畫重複次數,可以指定重複多次播放動畫
alphaAnimation.setRepeatMode(Animation.REVERSE);    //動畫重複播放模式,RESTART——重新開始    REVERSE——動畫倒放

XML實現
動畫的xml文件是需要放到項目的res/anim文件夾下的。

<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromAlpha="1"
    android:toAlpha="0.5">
</alpha>

通過AnimationUtils.loadAnimation方法加載動畫xml

Animation alphaAnimation = AnimationUtils.loadAnimation(Activity.this,
                        R.anim.alpha_animation);

Translate

代碼實現

//Type 指定動畫移動類型,ABSOLUTE——絕對座標值
//                      RELATIVE_TO_SELF——自身尺寸乘以value
//                      RELATIVE_TO_PARENT——父佈局尺寸乘以value
//Value 起始值,根據Type不同取值意義不同
Animation transAnimation = new TranslateAnimation(Animation.ABSOLUTE, 0f, Animation.ABSOLUTE,
                200f, Animation.ABSOLUTE, 0f, Animation.ABSOLUTE, 200f);

參數分爲四組分別爲:fromX,toX,fromY,toY,每一組有兩個參數第一個表明取值類型,第二個爲取值大小。

XML實現

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

四個屬性的取值類型只能是百分比,表示控件自身的百分比。

Scale

代碼實現

//value 起始值,乘以自身尺寸倍數
//pivotType  縮放圓心取值類型,
//           ABSOLUTE——絕對座標值
//           RELATIVE_TO_SELF——自身尺寸乘以value(如:value= 0.5則表示以自身中心點位原點就行縮放)
//           RELATIVE_TO_PARENT——父佈局尺寸乘以value
Animation scaleAnimation = new ScaleAnimation(1f, 1.5f, 1f, 1.5f,
                Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);

前四個參數分別爲:fromX、toX、fromY、toY,值爲float類型意爲自身尺寸的倍數。後四個參數是用來確定縮放原點位置的,如上述代碼所示是以控件中心爲縮放原點進行縮放的。不同的pivotType和pivotValue可以確定不同的縮放原點,具體取值參考上面的註釋。

XML實現

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

屬性取值同樣只能是百分比,表示控件自身的百分比。

Rotate

代碼實現

//value 起始值,乘以自身尺寸倍數
//pivotType  縮放圓心取值類型
//           ABSOLUTE——絕對座標值
//           RELATIVE_TO_SELF——自身尺寸乘以value(如:value= 0.5則表示以自身中心點位原點就行縮放)
//           RELATIVE_TO_PARENT——父佈局尺寸乘以value
 Animation rotateAnimation = new RotateAnimation(0, 360,
                Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);

前兩個參數確定旋轉的角度,後四個參數確定旋轉的原點,與ScaleAnimation參數含義相同。

XML實現

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromDegrees="0"
    android:toDegrees="360"
    android:pivotX="50%"
    android:pivotY="50%">
</rotate>

Animation Set

當需要使用多個Animation一起播放時,就要用到AnimationSet。如果某個屬性在AnimationSet和其子項Animation中同時設置,那麼AnimationSet中的屬性值會覆蓋其子項的屬性值。
代碼實現

AnimationSet animationSet = new AnimationSet(true);
animationSet.addAnimation(getTransAnimation());      //添加Animation
animationSet.addAnimation(getScaleAnimation());
animationSet.addAnimation(getRotateAnimation());
animationSet.addAnimation(getAlphaAnimation());

animationSet.setDuration(2000);       //動畫時間設置
animationSet.setFillAfter(false);     //動畫結束之後是否停留在結束爲止
animationSet.setFillBefore(true);     //動畫結束之後是否回到開始位置
animationSet.setRepeatCount(1);       //動畫重複次數,可以指定重複多次播放動畫
animationSet.setRepeatMode(Animation.REVERSE);    //動畫重複播放模式,RESTART——重新開始
                                                  //                REVERSE——動畫倒放

XML實現

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

    <alpha android:fromAlpha="1"
        android:toAlpha="0"/>

    <translate android:fromXDelta="0"
        android:toXDelta="100%"
        android:fromYDelta="0"
        android:toYDelta="100%"/>
</set>

Interpolator

差值器是用來定義動畫變化率的對象。Android系統提供了衆多的Interpolator,雖然繁多但是使用簡單,我們只需要知道每種Interpolator的使用效果就好了。

switch (id){
    case R.id.clear:
        mInterpolator = null;
        break;
    case R.id.AccelerateDecelerateInterpolator:
        //在動畫開始與結束的地方速率改變比較慢,在中間的時候加速
        interpolatorName = "AccelerateDecelerateInterpolator";
        mInterpolator = new AccelerateDecelerateInterpolator();
        break;
    case R.id.AccelerateInterpolator:
        //在動畫開始的地方速率改變比較慢,然後開始加速
        interpolatorName = "AccelerateInterpolator";
        mInterpolator = new AccelerateInterpolator();
        break;
    case R.id.AnticipateInterpolator:
        //開始的時候向後然後向前甩
        interpolatorName = "AnticipateInterpolator";
        mInterpolator = new AnticipateInterpolator();
        break;
    case R.id.AnticipateOvershootInterpolator:
        //開始的時候向後然後向前甩一定值後返回最後的值
        interpolatorName = "AnticipateOvershootInterpolator";
        mInterpolator = new AnticipateOvershootInterpolator();
        break;
    case R.id.BounceInterpolator:
        //動畫結束的時候彈起
        interpolatorName = "BounceInterpolator";
        mInterpolator = new BounceInterpolator();
        break;
    case R.id.CycleInterpolator:
        //動畫循環播放特定的次數,速率改變沿着正弦曲線
        interpolatorName = "CycleInterpolator";
        mInterpolator = new CycleInterpolator(7);
        break;
    case R.id.DecelerateInterpolator:
        //在動畫開始的地方快然後慢
        interpolatorName = "DecelerateInterpolator";
        mInterpolator = new DecelerateInterpolator();
        break;
    case R.id.LinearInterpolator:
        //以常量速率改變
        interpolatorName = "LinearInterpolator";
        mInterpolator = new LinearInterpolator();
        break;
    case R.id.OvershootInterpolator:
        //向前甩一定值後再回到原來位置
        interpolatorName = "OvershootInterpolator";
        mInterpolator = new OvershootInterpolator();
        break;
}

使用

animation.setInterpolator(mInterpolator);
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:shareInterpolator="@android:anim/accelerate_decelerate_interpolator"
    android:duration="2000"
    android:fillBefore="true"
    android:repeatMode="reverse">

    <alpha/>
    <scale/>
    <rotate/>
</set>

其他應用場景

Activity切換動畫

Intent activityAnimIntent = new Intent(AnimationActivity.this, ActivityAnimationActivity.class);
startActivity(activityAnimIntent);
//activity 切換動畫
overridePendingTransition(R.anim.activity_enter_alpha_animation,R.anim.activity_out_alpha_animation);

在startActivity之後使用overridePendingTransition來設置Activity進入和退出動畫。

PopupWindow顯示動畫

實現很簡單不多囉嗦了直接看代碼吧。

<style name="PopupWindowAnimationStyle">
    <item name="android:windowEnterAnimation">@anim/popup_enter_anim</item>
    <item name="android:windowExitAnimation">@anim/popup_exit_anim</item>
</style>
private void showImgPopupWindow(View anchor) {
    if (mPopupWindow == null) {
        ImageView view = new ImageView(this);
        view.setBackgroundColor(Color.parseColor("#FF989898"));
        view.setImageDrawable(getDrawable(R.mipmap.ic_launcher));

        mPopupWindow = new PopupWindow(view, anchor.getMeasuredWidth(), anchor.getMeasuredWidth());
        //設置動畫效果
        mPopupWindow.setAnimationStyle(R.style.PopupWindowAnimationStyle);
    }
    if (mPopupWindow.isShowing()) {
        mPopupWindow.dismiss();
    } else {
        mPopupWindow.showAsDropDown(anchor);
    }
}

Dialog顯示動畫

跟PopupWindow完全一個套路。

dialog.getWindow().setWindowAnimations(R.style.PopupWindowAnimationStyle);

還有如android.support.v4.app.Fragment的切換動畫(只有v4包中的Fragment才用視圖動畫)都很簡單就不提了。

ViewGroup的子控件進場動畫

LayoutAnimation是作用在ViewGroup上的,來爲ViewGroup的子控件的第一次進場提供動畫效果。如:LinearLayout、RelativeLayout和ListView等。

實現方式如下
第一步:在anim文件下定義動畫效果:

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

第二步:新建一個layout_animation.xml文件,以layoutAnimation標籤開頭:

<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
    android:animation="@anim/left_to_right_anim"
    android:animationOrder="normal"
    android:delay="0.2">
</layoutAnimation>

需要說明的是android:delay屬性,取值爲分數或者百分數,表示當前執行動畫效果的子控件延時其整個動畫過程的百分之多少執行。如取值0,所有的子控件同時執行動畫效果。取值1,當前子控件必須等上一個控件執行完動畫纔開始執行。

第三步:在想要實現動畫效果的ViewGroup中設置android:layoutAnimation="":

<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"

    android:layoutAnimation="@anim/layout_animation">

當然也有其代碼實現,相對xml實現要簡潔一點:

Animation animation = AnimationUtils.loadAnimation(this,R.anim.left_to_right_anim);
LayoutAnimationController controller = new LayoutAnimationController(animation);
controller.setDelay(0.2f);
controller.setOrder(LayoutAnimationController.ORDER_REVERSE);
rootView.setLayoutAnimation(controller);
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章