咱們如今有一個簡單需求:咱們的界面中有一個Button和一個ImageView ,咱們點擊ImageView產生點擊事件,而後咱們點擊Button來移動這個ImageView,讓這個ImageView沿着X軸移動500,而且在移動以後咱們再次點擊ImageView的點擊事件讓它響應咱們的ImageView的點擊事件!html
請記住咱們的第一個需求!咱們開始分析:java
Android起初有兩種動畫:Frame Animation(逐幀動畫) Tween Animation(補間動畫),可是在用的時候發現這兩種動畫有時候並不能知足咱們的一些須要,因此Google在Androi3.0的時候推出了(Property Animation)屬性動畫,至於爲何前邊的兩種動畫不能知足咱們的須要,請往下看:android
Frame Animation(逐幀動畫)app
逐幀動畫就是UI設計多張圖片組成一個動畫,而後將它們組合連接起來進行動畫播放。異步
該方式相似於早期電影的製做原理:具體實現方式就很少說了,你只須要讓大家的UI出多張圖片,而後你順序的組合就能夠(前提是UI給您作圖)
ide
Tween Animation(補間動畫) 性能
Tween Animation:是對某個View進行一系列的動畫的操做,包括淡入淡出(Alpha),縮放(Scale),平移(Translate),旋轉(Rotate)四種模式優化
我們用一個列子來講明這種方式:動畫
eg:首先咱們重建一個項目,而後寫一個xmllua
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <ImageView android:id="@+id/image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="click" android:background="@drawable/ic_launcher" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:onClick="move" android:text="Move" /> </RelativeLayout>
注:這個XML咱們後邊還會一直用到
接着咱們須要在咱們的Activity中加入代碼
package com.example.animator1; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.annotation.SuppressLint; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.ImageView; import android.view.animation.TranslateAnimation; import android.widget.Toast; public class Animator1Activity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_animator1); } public void click(View view){ Toast.makeText(getApplicationContext(), "clicked", Toast.LENGTH_SHORT).show(); } @SuppressLint("NewApi") public void move(View view){ TranslateAnimation animation = new TranslateAnimation(0, 500, 0, 0); animation.setDuration(1000); animation.setFillAfter(true); //當動畫中止後就會停留在動畫結束的位置 ImageView imageView = (ImageView) findViewById(R.id.image); imageView.startAnimation(animation); } }
而後咱們運行咱們的代碼會發現,咱們的動畫運行都沒問題,可是出現了一個問題,那就是咱們的click事件,在動畫位置移動以前咱們點擊ImageView是會打印出「clicked」,可是當咱們在動畫位置移動以後再次點擊ImageView,發現「clicked」不打印了,可是咱們點擊原先ImageView動畫移動以前的位置會發現點擊事件又是能夠,從這咱們就能夠得出一個結論:傳統的Animation動畫並不適用於作進行動畫交互的效果,並且Animation動畫的效果是重複調用咱們的Ondraw方法進行重繪,這樣會存在內存,性能的一些問題。
咱們能夠得出Tween Animation(補間動畫)的一些缺點:
1:Tween Animation(補間動畫)只是針對於View,超脫了View就沒法操做了,這句話的意思是:假如咱們須要對一個Button,ImageView,LinearLayout或者是其餘的繼承自View的各類組件進行動畫的操做時,Tween Animation是能夠幫咱們完成咱們須要完成的功能的,可是若是咱們須要用到對一個非View的對象進行動畫操做的話,那麼補間動畫就沒辦法實現了。舉個例子:好比咱們有一個自定義的View,在這個View中有一個Point對象用於管理座標,而後在onDraw()方法中的座標就是根據該Pointde座標值進行繪製的。也就是說,若是咱們能夠對Point對象進行動畫操做,那麼整個自定義的View,那麼整個自繼承View的當前類就都有了動畫,可是咱們的目的是不想讓View有動畫,只是對動畫中的Point座標產生動畫,這樣補間動畫就不能知足了。
2:Tween Animation動畫有四種動畫操做(移動,縮放,旋轉,淡入淡出),可是咱們如今有個需求就是將當前View的背景色進行改變呢?抱歉Tween Animation是不能幫助咱們實現的。
3:Tween Animation動畫只是改變View的顯示效果而已,可是不會真正的去改變View的屬性,舉個例子:咱們如今屏幕的頂部有一個小球,而後經過補間動畫讓他移動到右下角,而後咱們給這個小球添加了點擊事件,但願位置移動到右下角的時候點擊小球能的放大小球。可是點擊事件是絕對不會觸發的,緣由是補間動畫只是將該小球繪製到了屏幕的右下角,實際這個小球仍是停在屏幕的頂部,因此你在右下角點擊是沒有任何反應的。
因此根據這些問題Google在Android3.0以後推出了一種全新的動畫模式Property Animation(屬性動畫)。
Property Animatior(屬性動畫)
屬性動畫是Android3.0以後引進的,它更改的是動畫的實際屬性,在Tween Animation(補間動畫)中,其改變的是View的繪製效果,真正的View的屬性是改變不了的,好比你將你的Button位置移動以後你再次點擊Button是沒有任何點擊效果的,或者是你如何縮放你的Button大小,縮放後的有效的點擊區域仍是隻有你當初初始的Button的大小的點擊區域,其位置和大小的屬性並無改變。而在Property Animator(屬性動畫)中,改變的是動畫的實際屬性,如Button的縮放,Button的位置和大小屬性值都會發生改變。並且Property Animation不止能夠應用於View,還能夠應用於任何對象,Property Animation只是表示一個值在一段時間內的改變,當值改變時要作什麼事情徹底是你本身決定的。
在Property Animation中,能夠對動畫應用一下的屬性:
Duration:動畫的持續時間
TimeInterPolation:屬性值的計算方式,如先快後慢
TypeEvaluator:根據屬性的開始,結束值與TimeInterpolation計算出的因子計算出當前時間的屬性值
Repeat Count and behavoir:重複次數與方式,如播放3次,5次,無限循環,可讓此動畫一直重複,或者是播放完時再反向播放。
Animation sets:動畫集合,便可以同時對一個對象應用幾個動畫,這些動畫能夠同時播放也能夠對不一樣的動畫設置不一樣開始偏移。
Frame refresh delay:多少時間刷新一次,即每隔多長時間計算一次屬性值,默認爲10s,最終刷新時間還受系統進程的調度與硬件的影響。
屬性動畫有幾種模式:ObjectAnimator ViewAnimator AnimationSet TypeEvalutors TimeInterplator
ObjectAnimator:
真真實實的改變了動畫的屬性。咱們如今用ObjectAnimator的幾種實現方式實現剛纔咱們用Tween Animation的實現點擊按鈕圖片移動而且點擊圖片響應事件
eg:首先咱們須要用到上邊咱們定義的xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <ImageView android:id="@+id/image" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="click" android:background="@drawable/ic_launcher" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_centerHorizontal="true" android:onClick="move" android:text="Move" /> </RelativeLayout>
咱們用第一種方式實現:
1:主要看代碼:
package com.example.animator1; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.annotation.SuppressLint; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.ImageView; import android.view.animation.TranslateAnimation; import android.widget.Toast; public class Animator1Activity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_animator1); } public void click(View view){ Toast.makeText(getApplicationContext(), "clicked", Toast.LENGTH_SHORT).show(); } @SuppressLint("NewApi") public void move(View view){ //使用ObjectAnimator實現上述實現方式 //translationY :x軸移動, X:最終到達的位置 ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, "translationX", 0f, 500f); animator.setDuration(1000); animator.start(); } }
咱們先來看看 "ObjectAnimator.ofFloat"源碼:
/** * Constructs and returns an ObjectAnimator that animates between float values. A single * value implies that that value is the one being animated to. Two values imply starting * and ending values. More than two values imply a starting value, values to animate through * along the way, and an ending value (these values will be distributed evenly across * the duration of the animation). * * @param target The object whose property is to be animated. This object should * have a public method on it called <code>setName()</code>, where <code>name</code> is * the value of the <code>propertyName</code> parameter. * @param propertyName The name of the property being animated. * @param values A set of values that the animation will animate between over time. * @return An ObjectAnimator object that is set up to animate between the given values. */ public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) { ObjectAnimator anim = new ObjectAnimator(target, propertyName); anim.setFloatValues(values); return anim; }
從源碼中大體咱們能夠看出:target就是咱們要標識的Tag,propertyName:被設置動畫的屬性名稱, values:動畫移動的時間範圍
好,代碼咱們貼出來了,而後咱們來看看大體意思:
ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, "translationX", 0f, 500f);
咱們首先實例化了一個ObjectAnimator,而後咱們來看看參數
imageView:須要更改的View
translationX:沿着X周移動(注:此處有不少屬性,常見的有translationX,translationY,rotation,alpha,scaleX,scaleY)
0f, 500f :從X軸的0點位置移動到500
animator.setDuration(1000);
設置動畫移動過程的時間
animator.start();
開始咱們的動畫
好,咱們如今運行代碼發現這正是咱們須要的效果,而且在ImageView移動以後咱們再次點擊ImageView發現點擊事件仍是能夠被執行的,從這兒就證實了咱們先前所說。
咱們用第二種方式實現:(注:XML仍是用咱們原先定義好的XML)
1:主要看代碼:
package com.example.animator1; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.annotation.SuppressLint; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.ImageView; import android.view.animation.TranslateAnimation; import android.widget.Toast; public class Animator1Activity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_animator1); } public void click(View view){ Toast.makeText(getApplicationContext(), "clicked", Toast.LENGTH_SHORT).show(); } @SuppressLint("NewApi") public void move(View view){ //使用ObjectAnimator實現上述實現方式 //translationY :x軸移動, X:最終到達的位置 ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, "translationX", 0f, 500f); animator.setDuration(1000); animator.start(); } }
咱們看看多屬性動畫的執行:
1:咱們經過ObjectAnimator中的各類屬性進行動畫異步執行 旋轉-->X軸移動-->Y軸移動 eg:
// /** // * 多屬性同時改變 //咱們寫了三個動畫。咱們發現下邊這三句話是同時執行的,他是異步執行的,異步同時執行的 // */ ObjectAnimator.ofFloat(imageView, "rotation", 0f, 360f).setDuration(1000).start(); ObjectAnimator.ofFloat(imageView, "translationX", 0f, 200f).setDuration(1000).start(); ObjectAnimator.ofFloat(imageView, "translationY", 0f, 200f).setDuration(1000).start();
2:咱們發如今Android中給咱們封裝了一個ProperyValueHolder,這種寫法的好處是:ProperyValueHolder對界面進行了一系列的優化,這樣的優化讓咱們在使用的多個屬性動畫優化中更加方便和更加節省時間。 eg:
/** * PropertyValuesHolder:咱們發現用這種方式和上邊用三個start實現的方式同樣,那這樣寫有什麼好處呢,回答是:PropertyValuesHolder對動畫進行了一系列的優化,這樣的一些優化使得咱們在使用多個屬性動畫的時候 * 更加方便更加節省之間, */ PropertyValuesHolder pl1 = PropertyValuesHolder.ofFloat( "rotation", 0f, 360f); PropertyValuesHolder pl2 = PropertyValuesHolder.ofFloat( "translationX", 0f, 200f); PropertyValuesHolder pl3 = PropertyValuesHolder.ofFloat( "translationY", 0f, 200f); ObjectAnimator.ofPropertyValuesHolder(imageView, pl1, pl2, pl3).setDuration(1000).start();
3:咱們仍是沿用第一種的方式經過onFloat中的各類屬性實例化,而後咱們經過AnimatorSet來執行動畫。 eg:
ObjectAnimator animator1 = ObjectAnimator.ofFloat(imageView, "rotation", 0f, 360f); ObjectAnimator animator2 = ObjectAnimator.ofFloat(imageView, "translationX", 0f, 360f); ObjectAnimator animator3 = ObjectAnimator.ofFloat(imageView, "translationY", 0f, 360f); AnimatorSet set = new AnimatorSet(); /** * 1 //動畫異步同時執行 */ // set.playTogether(animator1, animator2, animator3); // set.setDuration(1000); // set.start(); /** * 2 //按照順序進行動畫的播放 */ // set.playSequentially(animator1, animator2, animator3); // set.setDuration(1000); // set.start(); /** * 3 //先從X軸和Y軸上同時移動 , 再在animator動畫中旋轉 */ set.play(animator2).with(animator3); set.play(animator1).after(animator2); set.setDuration(1000); set.start();