Android當中的動畫2—Tween動畫


    1、前言:

            在前一篇博客當中樓主介紹了一下關於DrawableAnimation的使用,今天來介紹一下關於Android當中的另外一種動畫的實現機制,那就是Tween Animation的實現(補間動畫)也有人稱呼它爲View動畫,這種動畫框架在Android3.0之前可爲是Android中的一家獨大,同時也讓我們開發人員精疲力盡,爲什麼這麼說呢?因爲View動畫,他操作的是View的改變,而View的一些具體的屬性是沒有改變的,最常見的就是我們給他設置的OnClickListener,view移動了,事件卻不跟着他進行移動,Google當然也不會容忍這種事發生,所以就在Android3.0以後的 版本當中推出了屬性動畫來解決我們開發人員所面臨的尷尬的問題。我們現在學習它也要掌握它的實現思想。好了,我們來看一看,它的實現吧

    2、正文:
        
        <1>、都有哪些動畫?
                其實現在看來我們的Tween Animation確實有一定的侷限性,因爲他只提供了,透明度,旋轉,縮放,位移這幾種常見的動畫,我們也可以這麼理解,就是如果我們掌握了透明度,旋轉,縮放,平移,外加它們這些動畫是怎麼實現的,自己去實現一個自己的動畫,那麼恭喜你,你可以過關,過關以後,去看樓主的下一篇博客,屬性動畫。

        <2>、Tween Animation的實現原理。
                剛剛在前面說過Tween Animation定義了幾種常見的動畫,其實它的實現,就是控制View,在每次繪製視圖的時候,去在View的ViewGroup中drawChild方法中獲取該View的Animation的Transformation值,canvas.concat(transfoemToApply.getMatrix()),通過矩陣去實現動畫的幀,如果該動畫沒有完成,則通過invalidate()方法進行不斷地重繪,從而達到整個動畫的繪製

            補充:首先我們應該明白在我們每一個View當中都有一個Animation對象,而這個對象當中有一個Transformation對象,而這個對象裏面維護了一個可以根據時間因子改變的Matrix,,然後我們通過canvas.concat(transfoemToApply.getMatrix())獲取我們的矩陣,從而實現我們的動畫,這一塊的內容我也會在後續博客當中跟大家說到。

        
        <3>、API,語法:

                我們的Tween Animation的實現,主要分成了兩部分,我們可以通過代碼去控制我們的動畫,我們也可以通過XML定義我們的動畫,定義好了以後我們只需要在代碼當中加載一下,便可以使用了,


        在此說一下我自己的想法,我們如果想要一個動畫效果,我們肯定需要很多的屬性去約束他,而我們可以把屬性放在XML當中,讓系統自己去加載,我們也可以在代碼裏面直接的通過參數的類型傳給我們的動畫,從而得到一個動畫的對象

            <1>、通過XML去定義動畫,如果我們要去定義一個XML的動畫,我們需要在/res/anim/目錄下創建相應的XML文件,

Alpha:淡入淡出動畫效果

<span style="font-size:18px;"><alpha   
	android:fromAlpha="1.0"    
	android:toAlpha="0.0"    
        android:duration="500"  />   
			     
<!--    
	fromAlpha:開始時透明度,透明度在0和1之間取值,類型是float類型   
	toAlpha: 結束時透明度 
	duration:動畫持續時間 
-->  </span>
 

rotate:旋轉效果

<span style="font-size:18px;"><rotate                                        
        android:interpolator="@android:anim/accelerate_decelerate_interpolator"   
        android:fromDegrees="300"   
        android:toDegrees="-360"   
        android:pivotX="10%"   
        android:pivotY="100%"   
        android:duration="10000" />      
<!--    
      fromDegrees   動畫開始時的角度
      toDegrees     動畫結束時物件的旋轉角度,正代表順時針     
      pivotX    屬性爲動畫相對於物件的X座標的開始位置  
      pivotY    屬性爲動畫相對於物件的Y座標的開始位置    
-->  
</span>

          

   scale:縮放效果:

<scale     
	android:interpolator= "@android:anim/decelerate_interpolator"         
	android:fromXScale="0.0"     
	android:toXScale="1.5"     
	android:fromYScale="0.0"     
	android:toYScale="1.5"     
	android:pivotX="50%"     
	android:pivotY="50%"     
	android:startOffset="0"     
	android:duration="10000"    
	android:repeatCount="1"     
	android:repeatMode="reverse"  />     
  
<!--    
	fromXDelta,fromYDelta       起始時X,Y座標,屏幕右下角的座標是X:320,Y:480   
	toXDelta, toYDelta      動畫結束時X,Y的座標 
--> 
<!--     
	fromXScale,fromYScale,         動畫開始前X,Y的縮放,0.0爲不顯示,1.0爲正常大小  
	toXScale,toYScale,		動畫最終縮放的倍數, 1.0爲正常大小,大於1.0放大  
	pivotX,  pivotY		動畫起始位置,相對於屏幕的百分比,兩個都爲50%表示動畫從屏幕中間開始   
	startOffset,			動畫多次執行的間隔時間,如果只執行一次,執行前會暫停這段時間,單位毫秒 
	duration,			一次動畫效果消耗的時間,單位毫秒,值越小動畫速度越快 
	repeatCount,			動畫重複的計數,動畫將會執行該值+1次   
        repeatMode,			動畫重複的模式,reverse爲反向,當第偶次執行時,動畫方向會相反。restart爲重新執行,方向不變 
--> 

translate.xml 移動效果:

<set xmlns:android="http://schemas.android.com/apk/res/android">  
    <translate   
        android:fromXDelta="320"   
        android:toXDelta="0"   
        android:fromYDelta="480"   
        android:toYDelta="0"   
        android:duration="10000" />   
</set>   

<!--    
    fromXDelta,fromYDelta   起始時X,Y座標,屏幕右下角的座標是X:320,Y:480   
    toXDelta, toYDelta     動畫結束時X,Y的座標 
-->   

下面單獨說說關於interpolator
    指定動畫插入器,所謂的插入器,說白了就是用來控制動畫速度的一個控制器而在XML當中可以使用的是三種,分別是
        accelerate_decelerate_interpolator    先加速-後減速插入器
        accelerate_interpolator,        加速插入器    
        decelerate_interpolator。        減速插入器

當我們定義完成以後呢,我們就可以在Java代碼當中使用

 Animation animation = AnimationUtils.loadAnimation(this, R.anim.XXXX);
 view.startAnimation(animation);

以上就是我們使用XML來定義動畫的API。下面我們來看看如何使用代碼來實現我們的動畫,如果我們要去使用代碼來實現動畫,首先我還是要在這裏給大家介紹代碼API

           在這裏我們首先來看動畫的抽象類,Animation,這個類是Tween Animation動畫具體實現類的基類,提供了動畫啓動,停止,重複,持續時間等方法

                   Animation 有如下常用方法:

                      setDuration(long time)    設置動畫持續時間,單位爲毫秒。

                      startNow(); 啓動動畫的主要方法,使用之前必須先使用setAnimation()爲某一個View對象設置動畫,另外用戶可以是用View組件的startAnimation();來啓動動畫。

                      start();和上述方法功能一直,區別在與該方法可以用於getTransfoemation();方法被調用時啓動動畫

                      cancel();用戶取消動畫,

                      setRepeatCount(int repeatCount);設置動畫重複次數,設置爲n 執行n+1次動畫,爲-1,一直

                      setFillEnables(boolean fillEnabled);根據boolean值來實現是否開啓填充效果,

                      setRepeatMode(int repeatMode):RESTART:重新從頭開始,REVERSE:表示反方向執行

                       setSatartOffset(long startOffset):動畫延遲startOffset毫秒開始執行。


                    AlphaAnimation:透明度變換動畫:

                  new AlphaAnimation(float fromAlpha, float toAlpha);構建透明度漸變動畫,從fromAlpha到toAlpha


                    ScaleAnimation:縮放動畫:

                    new ScaleAnimation(float fromX, float toX, float fromY, float toY, int pivotXType, folatpivotXValus,int pivotYType, folatpivotYValus);以(<pivotXType模式,pivotXValus的值>,<pivotYType模式,pivotYValus的值>)座標點爲縮放中心,在X方向比例從fromX到toX,在Y方向比例從fromY到toY。


                   TranslateAnimation:平移動畫:

                      newTranslateAnimation(float fromXDelta, float toXDelta,float fromYDelta,float toYDelta);座標點從( fromXDelta, fromYDelta)到(toXDeltatoYDelta


                    RotateAnimation:旋轉動畫:

                       newRotateAnimation(float fromDegress, float toDegress,int pivotXType, folat pivotXValus, int pivotYType, folatpivotYValus)以(<pivotXType模式,pivotXValus的值>,<pivotYType模式,pivotYValus的值>)座標點爲旋轉中心,從fromDegress度旋轉到toDegress


關於動畫的插值器,(Interpolators)的使用。

              AccelerateDecelerateInterpolators:慢慢開始和結束,在中間加速。

              AccelerateInterpolators:慢慢開始,然後加快速度。

              AnticipateInterpolator:開始向後,然後向前

              AnticipateOvershootInterpolator:開始向後,然後向前,超過目標值,然後返回目標值

              BounceInterpolator:動畫在結束的時候彈起

              CycleInterpolator:動畫循環特定的次數,速率變化方式爲正玄曲線

              DecelerateInterpolator:開始快,然後慢

              LinearInterpolator:以恆定的速率變化

              OvershootInterpolator:向前衝一定值後再回到原來的位置


TimeInterpolator:這一個比較特殊,它的存在就是爲我們自定義而生的,在下一節樓主的博客中,爲大家詳細講解


        以上就是動畫的所有API,但是我們的問題來了,如果我想對一個View同時去執行多個動畫的時候我們應該怎麼辦呢。這個時候我們就又要介紹另外的一個API了,那就是AniamtionSet,其實大家可以把它想象成爲是一個動畫的集合,我們把我們所拿到的多個動畫放入其中,然後讓我們的View對象去開啓他就OK了,好了,下面我們直接開始一個Animation的小Demo,讓大家可以更好地去理解我們的的Tween Animation。


我們通過幾個Button去控制我們的動畫,然後用一個ImageView作爲這個動畫的載體,就這麼簡單。




大家會覺得爲什麼在縮放上面的變換不是很平滑呢,那是樓主在上面加入了插值器的效果,插值器效果很多,在這裏樓主就不一一列舉了,下面給大家看代碼,/res/layout/activity_main.xml


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <ImageView
        android:id="@+id/image"
        android:padding="20dip"
        android:layout_width="match_parent"
        android:layout_height="350dip"
        android:src="@mipmap/empty_logo_black"
        />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        >

        <Button
            android:layout_width="0dip"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimary"
            android:text="透明度"
            android:onClick="alpha"
            android:textColor="#fff"/>

        <Button
            android:layout_width="0dip"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimary"
            android:text="縮放"
            android:onClick="scale"
            android:textColor="#fff"/>

        <Button
            android:layout_width="0dip"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimary"
            android:onClick="rotate"
            android:text="旋轉"
            android:textColor="#fff"/>

        <Button
            android:layout_width="0dip"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimary"
            android:text="平移"
            android:onClick="translate"
            android:textColor="#fff"/>
        <Button
            android:layout_width="0dip"
            android:layout_weight="1"
            android:layout_height="wrap_content"
            android:background="@color/colorPrimary"
            android:text="全部"
            android:onClick="all"
            android:textColor="#fff"/>


    </LinearLayout>


</RelativeLayout>

Java代碼如下所示,MainActivity.Java


package com.suansuan.tweenanimation;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.AnimationSet;
import android.view.animation.AnticipateOvershootInterpolator;
import android.view.animation.RotateAnimation;
import android.view.animation.ScaleAnimation;
import android.view.animation.TranslateAnimation;
import android.widget.ImageView;

public class MainActivity extends AppCompatActivity {

    private ImageView mImage;

    private long duration = 1000;

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

    /** 淡入淡出動畫 */
    public void alpha(View view){
        AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0);
        alphaAnimation.setDuration(duration);

        //保持最後的狀態,
        alphaAnimation.setFillAfter(true);
        mImage.startAnimation(alphaAnimation);
    }

    /** 縮放動畫 */
    public void scale(View view){
        ScaleAnimation scaleAnimation = new ScaleAnimation(1f, 0f, 1f, 0f,ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
                ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
        scaleAnimation.setDuration(duration);
        scaleAnimation.setInterpolator(new AnticipateOvershootInterpolator());
        //保持最後的狀態,
        scaleAnimation.setFillAfter(true);
        mImage.startAnimation(scaleAnimation);
    }

    /** 旋轉動畫 */
    public void rotate(View view){

        RotateAnimation rotateAnimation = new RotateAnimation(0f, 360f, ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
                ScaleAnimation.RELATIVE_TO_SELF, 0.5f);

        rotateAnimation.setDuration(duration);

        //保持最後的狀態,
        rotateAnimation.setFillAfter(true);
        mImage.startAnimation(rotateAnimation);
    }

    /** 平移動畫 */
    public void translate(View view){
        TranslateAnimation translateAnimation = new TranslateAnimation(0, 0, 0, 500);
        translateAnimation.setDuration(duration);

        //保持最後的狀態,
        translateAnimation.setFillAfter(true);
        mImage.startAnimation(translateAnimation);
    }

    /** 使用AnimationSet全部執行 */
    public void all(View view){
        AnimationSet animationSet = new AnimationSet(false);

        AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0);
        animationSet.addAnimation(alphaAnimation);
        ScaleAnimation scaleAnimation = new ScaleAnimation(1f, 0f, 1f, 0f,ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
                ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
        animationSet.addAnimation(scaleAnimation);
        RotateAnimation rotateAnimation = new RotateAnimation(0f, 360f, ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
                ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
        animationSet.addAnimation(rotateAnimation);
        TranslateAnimation translateAnimation = new TranslateAnimation(0, 0, 0, 500);
        animationSet.addAnimation(translateAnimation);
        animationSet.setDuration(6000);

        mImage.startAnimation(animationSet);
    }
}

最後一點,我說說動畫的監聽吧,

<pre name="code" class="java">  mAnimation.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                //動畫將要開始的時候的監聽回調
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                //動畫結束的時候的監聽回調
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
                //當動畫重複時回調
            }
        });


 


好了 以上就是我們Tween Animation的基礎知識,其實在我們平時開發當中還有好多,一篇博客根部就寫不完,所以在這裏說下常用的基礎知識。好了,下面我們去做一個練習,我們做一個在我們的ListView下拉的時候,我們下來出來的Item增加動畫效果,好了我們先看一下效果,很簡單對吧,但是有很多的Bug,沒關係,我們學習了屬性動畫以後會在很大的程度上面去改變,去優化的。

我們去看看是怎麼實現的把,我們這裏使用到了一個開源的庫,而這個庫的作用就是隨機生成好看的顏色,

compile 'com.github.lzyzsd.randomcolor:library:1.0.0'
這就是這個庫的鏈接,如果是使用Eclipse的同學,請到Github上面下載,我們先看資源文件/res/layout/activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:padding="5dip"
    android:layout_height="match_parent">

    <ListView
        android:id="@+id/lv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:dividerHeight="5dip"
        />
</LinearLayout>

很簡短,就是一個ListView。


package com.suansuan.textapplication.textanimator;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AlphaAnimation;
import android.view.animation.AnimationSet;
import android.view.animation.AnticipateOvershootInterpolator;
import android.view.animation.ScaleAnimation;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;

import com.github.lzyzsd.randomcolor.RandomColor;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private AnimationSet mAnimation;
    private List<Integer> list;

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

    /** 初始化View */
    private void initView() {
        ListView mListView = (ListView) findViewById(R.id.lv);
        initAnimation();
        list = new ArrayList<>();
        mListView.setAdapter(new MyAdapter());
    }

    /** 初始化Animation */
    private void initAnimation() {
        mAnimation = new AnimationSet(true);
        ScaleAnimation scaleAnimation = new ScaleAnimation(0.8f, 1f, 1f, 1f, ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
                ScaleAnimation.RELATIVE_TO_SELF, 0.5f);
        mAnimation.addAnimation(scaleAnimation);
        AlphaAnimation alphaAnimation = new AlphaAnimation(0.2f, 1f);
        mAnimation.addAnimation(alphaAnimation);

        mAnimation.setDuration(1000);
        mAnimation.setInterpolator(new AnticipateOvershootInterpolator());
    }

    /** ListView的數據適配器 */
    class MyAdapter extends BaseAdapter{

        @Override
        public int getCount() {
            return 20;
        }

        @Override
        public Object getItem(int position) {
            return null;
        }

        @Override
        public long getItemId(int position) {
            return 0;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            RandomColor randomColor = new RandomColor();
            if(convertView == null){
                convertView = new ImageView(getApplicationContext());
                AbsListView.LayoutParams layoutParams = new AbsListView.LayoutParams(AbsListView.LayoutParams.MATCH_PARENT, 400);
                convertView.setLayoutParams(layoutParams);
                convertView.setBackgroundColor(randomColor.randomColor());
            }else{
                convertView.setBackgroundColor(randomColor.randomColor());
            }

            /** 使用List的原因就是在我們的Item第一次出來的時候進行動畫展示,以後不用再做動畫展示 */
            if (!list.contains(position)) {
                convertView.startAnimation(mAnimation);
                list.add(position);
            }

            return convertView;
        }
    }

}

好了,今天的博客就到這裏了,感謝各位觀看,我們一起努力,一起快樂的碼代碼,我是劉酸酸,有錯請指出,謝謝



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章