android應用開發(fā)動畫匯總

一般情況下,動畫并不會影響我們應用的業(yè)務邏輯,但沒有動畫會讓我們的應用顯得過于死板,沒有活力與競爭力。

android中的動畫大致可以分為三類:view動畫,幀動畫與屬性動畫。

我們先來看view動畫:

view動畫表示繼承自Animation的一類動畫,包括對view的平移,縮放,透明度,旋轉。即:TranslateAnimation,ScaleAnimation,AlphaAnimation,RotateAnimation。這四種動畫可以可以通過xml文件定義,如在res/anim/animation.xml定義,也可以在代碼中寫,但在xml中比在代碼中寫要方便的多。當然除了這四種類型,我們也可以通過AnimationSet類將這四種動畫組合使用。我們就以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"] >
<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>

android:shareInterpolator屬性表示動畫是否共享同一個插值器,interpolator表示插值器,也可以通過setInterpolator()方法傳入一個插值器對象,下面簡單介紹一些常見的插值器:

AccelerateDecelerateInterpolator
先加速再減速。這是默認的 Interpolator,也就是說如果你不設置的話,那么動畫將會使用這個 Interpolator。

LinearInterpolator
勻速。

AccelerateInterpolator
持續(xù)加速。在整個動畫過程中,一直在加速,直到動畫結束的一瞬間,直接停止。

DecelerateInterpolator
持續(xù)減速直到 0。動畫開始的時候是最高速度,然后在動畫過程中逐漸減速,直到動畫結束的時候恰好減速到 0。

AnticipateInterpolator
先回拉一段位移再進行正常動畫軌跡。

OvershootInterpolator
動畫會超過目標區(qū)域再彈回。

AnticipateOvershootInterpolator
AnticipateInterpolator與OvershootInterpolator的結合版:開始前回拉,最后超過一段位移然后彈回。

BounceInterpolator
在目標區(qū)域來回彈跳,直至停止。

CycleInterpolator
動畫可以提前到達目標區(qū)域,也可以到達目標區(qū)域后回彈,由構造函數參數決定。

PathInterpolator
Path路徑的坐標表示動畫完成度 / 時間完成度曲線。這是一個自定義的動畫模型,根據你想要達到的效果來自定義動畫完成度與時間的關系。但不允許同一時間有兩個動畫完成度出現,否則會報fc。

FastOutLinearInInterpolator
類似于AccelerateInterpolator,不過它在開始加速過程中速度會較快,加速度較大,不過差別也比較小,很難發(fā)現區(qū)別。

FastOutSlowInInterpolator
類似于AccelerateDecelerateInterpolator,先加速,后減速,在加速與減速階段加速度都較大。

LinearOutSlowInInterpolator
類似于DecelerateInterpolator,開始達到速度最大值,然后一路減速運行,不過初始速度會比較高,減速較快。

插值器就簡單介紹到這里。

加載xml動畫也比較簡單,通過AnimationUtils類來實現:

  AnimationUtils.loadAnimation(this, R.anim.animation);

通過setAnimationListener可以為Animation設置監(jiān)聽器:

 animation.setAnimationListener(new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {

        }

        @Override
        public void onAnimationEnd(Animation animation) {

        }

        @Override
        public void onAnimationRepeat(Animation animation) {

        }
    });

如果我們想讓view停留在動畫結束的地方, 可以通過調用fillAfter()方法來實現:

    animation.setFillAfter(true);

不過這里需要注意的是,雖然view看上去停留在了動畫結束的地方,但當我們觸發(fā)view的監(jiān)聽事件時,發(fā)現并沒有起作用,而只有在點擊原來的位置才能觸發(fā)監(jiān)聽事件,這并不是android的bug,這是因為view動畫只是view的影像,而view本身的屬性并沒有發(fā)生改變。

另外如果當你在動畫結束需要設置view的visibility屬性時,需要先清除動畫,否則將不起作用。

 view.clearAnimation();

幀動畫:

幀動畫表示view切換過程中的動畫效果,可以是activity之間的切換,也可以是view的切換。activity之間的切換可能是用的比較多的一類幀動畫,當我們需要銷毀或啟動一個activity時,在finish()或startActivity()后面跟上如下代碼:

  overridePendingTransition(enterAnim, exitAnim);

就能實現activity之間的切換動畫,比如,如果要實現右滑的效果:

slide_left_in.xml

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

slide_right_out.xml

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

在finish()或startActivity()后面增加:

 overridePendingTransition(R.anim.slide_in_left, R.anim.slide_out_right);

如果進行view之間的動畫切換,我們可以借助AnimationDrawable來實現,比如:

frame_animation.xml

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="@android:color/white" android:duration="500"></item>
<item android:drawable="@android:color/holo_green_dark" android:duration="500"></item>
<item android:drawable="@android:color/black" android:duration="500"></item>
</animation-list>

在activity通過如下調用:

view = findViewById(R.id.activity_main);
view.setBackgroundResource(R.drawable.frame_animation);
view.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            AnimationDrawable aniDrawable = (AnimationDrawable) view.getBackground();
            aniDrawable.start();
        }
    });

我這里只是更改了view的背景色,當然你也可以將android:drawable屬性設為你喜歡的圖像。

接下來讓我們看一下屬性動畫:

在我們的應用開發(fā)中,屬性動畫一般是用的最多的一類動畫,屬性動畫區(qū)別于其它動畫的最主要特征是view的屬性值的改變。屬性動畫是android 3.0(API 11)之后的產物,相對傳統(tǒng)動畫能實現更豐富的動畫效果。如果android 3.0之前的版本也想使用屬性動畫,可以采用nineoldandroids開源動畫庫,網址是:http://nineoldandroids.com.屬性動畫從實現上由簡到難可大致分為ViewAnimator,ObjectAnimator,ValueAnimator。

我們首先來看ViewAnimator,這里主要用到的是它的子類ViewPropertyAnimator。ViewPropertyAnimator動畫的使用來源于view的四大轉換,即我們熟悉的平移,縮放,旋轉以及透明度。即:

view.setTranslationX(float translationX);
view.setTranslationY(float translationY);
view.setTranslationZ(float translationZ);
    
view.setScaleX(float scaleX);
view.setScaleY(float scaleY);
    
view.setRotation(float rotation);
view.setRotationX(float rotationX);
view.setRotationY(float rotationY);
    
view.setAlpha(float alpha);

使用上也很簡單,一行代碼即可搞定:

view.animate().translationX(500);

也可以基于之前的位置進行動畫處理:

view.animate().translationYBy(500);

其它的動畫也類似,就不舉例了,當然除了這些單一的動畫,還可以多種動畫同時進行,比如這種寫法:

view.animate()
            .translationX(500)
            .scaleY(4)
            .rotation(360)
            .alpha(0.5f);

屬性動畫一般可以同時設置兩種類型的監(jiān)聽器:

view.animate().setListener(new Animator.AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animation) {

        }

        @Override
        public void onAnimationEnd(Animator animation) {

        }

        @Override
        public void onAnimationCancel(Animator animation) {

        }

        @Override
        public void onAnimationRepeat(Animator animation) {

        }
    });

表示了動畫的執(zhí)行周期回調。

view.animate().setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {

        }
    });

表明動畫在執(zhí)行過程中的回調,每一幀(不確切的說為10ms)就會進行一次回調,根據這個回調我們就可以在動畫執(zhí)行過程中處理一些事情。

相比于ViewPropertyAnimator,ObjectAnimator功能更強大,但同樣操作起來也更復雜,ObjectAnimator通過不斷更改屬性值而實現的,我們先看看ObjectAnimator如何實現動畫效果。

比如我們需要不斷更改ProgressBar的進度條來實現動畫效果,我們就可以這樣寫:

ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar);
ObjectAnimator animator = ObjectAnimator.ofInt(progressBar, "progress", 0, 100);
animator.start();

這里有幾點需要注意:
1.由于progress是值是int型,所以我們需要用到ofInt方法來生成ObjectAnimator方法,ofFloat()也一樣,而顏色卻不能這樣使用,因為我們知道通過argb來表示顏色的話每個Byte都有不同的意義,而不能通過簡簡單單的int值去處理,所以android給我們提供了ofArgb()專門用于處理顏色變幻的。

2."progress"屬性必須存在,而且必須有提供好的setProgress()與getProgress()(當構造中沒有傳入progress初始值時必須提供get方法,否則會fc)。

另外我們也可以通過使用AnimatorSet讓我們的動畫同時進行,如:

AnimatorSet aniSet = new AnimatorSet();
aniSet.playTogether(animator1, animator2);

也可以按一定順序執(zhí)行:

AnimatorSet aniSet = new AnimatorSet();
aniSet.playSequentially(animator2, animator1);

也可以使用PropertyValuesHolder:

PropertyValuesHolder scaleXHolder = PropertyValuesHolder.ofFloat("scaleX", 0, 1);
PropertyValuesHolder scaleYHolder = PropertyValuesHolder.ofFloat("scaleY", 0, 1);
PropertyValuesHolder alphaHolder = PropertyValuesHolder.ofFloat("alpha", 0, 1);

ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view, scaleXHolder, scaleYHolder, alphaHolder);
animator.start();

也可以是同一個動畫的不同階段,即動畫完成度/動畫時間:

Keyframe step1 = Keyframe.ofFloat(0, 0);
Keyframe step2 = Keyframe.ofFloat(0.5f, 100);
Keyframe step3 = Keyframe.ofFloat(1, 50);
PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("progress", step1, step2, step3);
ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view, holder);
animator.start();

當然除了系統(tǒng)為我們提供好的屬性外,我們也可以在控件中定義自己的屬性。這個時候就要用到,比如:

ObjectAnimator animator = ObjectAnimator.ofObject(view, "position",
new PointFEvaluator(), new PointF(0, 0), new PointF(1, 1));
animator.setDuration(1000);
animator.start();

由于position屬性是一個坐標點,即PointF對象,系統(tǒng)并沒有為我們提供具體的接口,這個時候就需要我們自己來實現,通過ofObject,而且我們的自定義view中必須有position屬性與setPosition方法。由于實現的是ofObject方法,所以這里我們需要實現自己的估值器,實現TypeEvaluator()接口。

private class PointFEvaluator implements TypeEvaluator<PointF> {

    // 重寫 evaluate() 方法,讓 PointF 可以作為屬性來做動畫
    @Override
    public PointF evaluate(float fraction, PointF startValue, PointF endValue) {
        PointF outPointF = new PointF();
        outPointF.x = startValue.x + (endValue.x - startValue.x) * fraction;
        outPointF.y = startValue.y + (endValue.y - startValue.y) * fraction;
        return outPointF;
    }
}

最后讓我們來看看ValueAnimator,ValueAnimator是ObjectAnimator的父類,但ValueAnimator并不能指定動畫的目標,所以如果我們想要使用ValueAnimator達到動畫的效果,那么我們可以通過實現TypeEvaluator接口,在每一幀動畫到來時去invalidate()目標view達到動畫的效果。

接下來要說的一些動畫我們可能用的比較少,但對于我們工程師來說,卻能讓我們的應用看起來更炫。

第一個要說的是LayoutAnimation,LayoutAnimation主要作用于ViewGroup,它也是一種view動畫,常常作用在ListView或GridView上,這樣當子view出場時就有了一定的動效。

layout_animation.xml

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

main.xml

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

...
android:id="@+id/listview"
android:layoutAnimation="@anim/layout_animation"
...
/>

除了在xml指定動畫效果外,還可以在代碼中指定:

listview = findViewById(R.id.listview);
Animation animation = AnimationUtils.loadAnimation(this, R.anim.layout_animation);
LayoutAnimationController controller = new LayoutAnimationController(animation);
controller.setDelay(0.5f);
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
listView.setLayoutAnimation(controller);

接下來說的是gif動畫,也就是播放一張gif圖片。這個我也是參考的網上的博文,就不講了,這里有一篇不錯的文章大家可以看一下:http://blog.csdn.net/guolin_blog/article/details/11100315

最后再講一下3D動畫,3D動畫主要包含三類,旋轉,平移,移動相機,3D動畫主要用到的是Camera這個類,它的原理是通過Camera對view進行投影從而達到3d的效果,Camera使用的是3D坐標系,仍然以左上角為坐標原點(0,0,0),這點與Canvas保持一致,x族為右正左負,y族上正下負,z族垂直于屏幕外正內負。旋轉方向為以沿x族上方從屏幕外向里為x正向旋轉,沿y族順時針方向為y正向旋轉,沿z族從右向左為z正向旋轉。Camera默認坐標位置為(0,0,-576),我們可以通過setLocation調整它的位置。

我們通過一個例子來看如何實現3D效果:

首先需要自定義一個3D動畫:

public class Rotate3DAnimation extends Animation {

private final float mFromDegrees;
private final float mToDegrees;
private final float mCenterX;
private final float mCenterY;
private final float mDepthZ;
private boolean mReverse;
private Camera mCamera;
private float scale = 2.5f;

/**
 * 創(chuàng)建一個繞y軸旋轉的3D動畫效果,旋轉過程中具有深度調節(jié),可以指定旋轉中心。
 *
 * @param fromDegrees   起始時角度
 * @param toDegrees     結束時角度
 * @param centerX       旋轉中心x坐標
 * @param centerY       旋轉中心y坐標
 * @param depthZ        最遠到達的z軸坐標
 * @param reverse       true 表示由從0到depthZ,false相反
 */
public Rotate3DAnimation(float fromDegrees, float toDegrees,
                         float centerX, float centerY, float depthZ, boolean reverse) {
    mFromDegrees = fromDegrees;
    mToDegrees = toDegrees;
    mCenterX = centerX;
    mCenterY = centerY;
    mDepthZ = depthZ;
    mReverse = reverse;
}

@Override
public void initialize(int width, int height, int parentWidth, int parentHeight) {
    super.initialize(width, height, parentWidth, parentHeight);
    mCamera = new Camera();
}

@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
    final float fromDegrees = mFromDegrees;
    float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);
    final float centerX = mCenterX;
    final float centerY = mCenterY;
    final Camera camera = mCamera;
    final Matrix matrix = t.getMatrix();
    camera.save();
    mReverse = interpolatedTime < 0.5?true:false;
    // 調節(jié)深度
    if (mReverse) {
        camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
    } else {
        camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
    }

    // 繞y軸旋轉
    camera.rotateX(degrees);

    camera.getMatrix(matrix);
    camera.restore();

    // 修正失真,主要修改 MPERSP_0 和 MPERSP_1
    float[] mValues = new float[9];
    matrix.getValues(mValues);              //獲取數值
    mValues[6] = mValues[6]/scale;          //數值修正
    mValues[7] = mValues[7]/scale;          //數值修正
    matrix.setValues(mValues);              //重新賦值

    // 調節(jié)中心點
    matrix.preTranslate(-centerX, -centerY);
    matrix.postTranslate(centerX, centerY);
}
}

在Activity調用:

Rotate3DAnimation rotate3D = new Rotate3DAnimation(0, 90, view.getWidth()/2, view.getHeight()/2, 0, false);
rotate3D.setDuration(1000);
rotate3D.setFillAfter(true);
view.startAnimation(rotate3D);

這里要注意的是Camera對動畫的執(zhí)行是反序的,不過我們可以通過preTranslate或postTranslate指定動畫順序,即先將view平移到原點,然后繞x旋轉,最后將旋轉后的結果在平移到原來的位置。

到這里所有動畫相關的內容就結束了,如果有什么問題,希望給我留言。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,362評論 6 537
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 99,013評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,346評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,421評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,146評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,534評論 1 325
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,585評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,767評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 49,318評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,074評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,258評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,828評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,486評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,916評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,156評論 1 290
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,993評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,234評論 2 375

推薦閱讀更多精彩內容