android動畫使用大全
android中主要有三種方式來實現動畫,補間動畫、幀動畫、屬性動畫。
1.補間動畫(tween Animation)
補間動畫就是對影象進行
- 平移 translate
- 縮放 schale
- 旋轉 rotale
- 漸變alpha
xml使用補間動畫
下面建立一個rotate.xml,裡面有四組標籤分別是,旋轉、縮放、漸變、平移,我們可以在set標籤中組合使用這些動畫標籤。
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" > <rotate android:fromDegrees="0" android:pivotX="50%" android:pivotY="30%" android:toDegrees="360"> </rotate> <scale></scale> <alpha></alpha> <translate></translate> </set>
這四種動畫實現方式都是通過Animation類和AnimationUtils配合實現,也可以通過xml實現,動畫的XML檔案在工程中res/anim目錄。
通過AnimationUtils.loadAnimation方法來載入剛剛定義的動畫配置。
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); Animation anim = AnimationUtils.loadAnimation(mContext, R.anim.rotate); //監聽動畫的狀態(開始,結束) anim.setAnimationListener(new EffectAnimationListener()); textWidget = (TextView)findViewById(R.id.text_widget); textWidget.setText("畫面旋轉動畫效果"); textWidget.startAnimation(anim); }
2. 程式碼中使用補間動畫
可以看到每個補間動畫都對應一個類,不同動畫效果選擇不同的類,它們都是Animation的子類。
private void startAlpha() { AlphaAnimation alpha = new AlphaAnimation(0.0f, 1f); alpha.setDuration(1000); but.startAnimation(alpha); } private void startScale() { ScaleAnimation scale = new ScaleAnimation(0.1f, 1.2f, 0.1f, 1.2f); scale.setDuration(1000); but.startAnimation(scale); } private void startTrans() { TranslateAnimation trans = new TranslateAnimation(0, 1, 0, 1); trans.setDuration(1000); but.startAnimation(trans); } private void starRotate() { RotateAnimation rotate = new RotateAnimation(0.1f, 1.1f); rotate.setDuration(1000); but.startAnimation(rotate); } @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.i("jinwei", "onCreate"); setContentView(R.layout.layout_glide); but = findViewById(R.id.but); img = findViewById(R.id.iamge); initLRUCache(); findViewById(R.id.but).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startAlpha(); startScale(); startTrans(); starRotate(); } }); }
AnimationSet動畫集合
private void startTrans() { AnimationSet set = new AnimationSet(true); TranslateAnimation trans = new TranslateAnimation(0, 1, 0, 1); trans.setDuration(1000); RotateAnimation rotate = new RotateAnimation(0.1f, 1.1f); rotate.setDuration(1000); }
2. 逐幀動畫(frame-by-frame animation)
逐幀動畫就是類似於動畫片似的,一張一張圖片連貫的播放,就可以動畫的效果。
Frame Animation
幀動畫順序播放設定好的圖片,就像電影一樣一幀一幀的播放。
<?xml version="1.0" encoding="utf-8"?> <animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="true" > <item android:drawable="@drawable/p1" android:duration="1000"></item> <item android:drawable="@drawable/p2" android:duration="1000"></item> <item android:drawable="@drawable/p3" android:duration="1000"></item> <item android:drawable="@drawable/p4" android:duration="1000"></item> <item android:drawable="@drawable/p5" android:duration="1000"></item> <item android:drawable="@drawable/p6" android:duration="1000"></item> </animation-list>
@Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.layout_glide); findViewById(R.id.but).setOnClickListener(new View.OnClickListener() { AnimationDrawable anim = (AnimationDrawable)getResources(). Drawable anim = getDrawable(R.drawable.frame); textWidget = (TextView)findViewById(R.id.text_widget); textWidget.setText("背景漸變動畫效果"); textWidget.setBackgroundDrawable(anim); anim.start(); } }
3. 補間動畫原理
整套動畫的執行邏輯還是很複雜的,我們只做最基本的瞭解,明白動畫是靠什麼執行變換的。
- 1.首先看view.startAnimation()
/** * Start the specified animation now. * * @param animation the animation to start now */ public void startAnimation(Animation animation) { animation.setStartTime(Animation.START_ON_FIRST_FRAME); setAnimation(animation); invalidateParentCaches(); invalidate(true); }
-
- setAnimation方法把定義的animation傳給了view,這裡可以看出最終的動畫呼叫邏輯肯定是在view中完成的,接著invalidate返回會重新整理view也就是會呼叫draw()方法。
-
3.draw()
可以補間動畫的效果主要是通過Matrix來完成的,操作縮放、位移、旋轉、傾斜的工具類。
if (transformToApply != null) { if (concatMatrix) { if (drawingWithRenderNode) { // 應用動畫資料 renderNode.setAnimationMatrix(transformToApply.getMatrix()); } else { canvas.translate(-transX, -transY); // 應用動畫資料 canvas.concat(transformToApply.getMatrix()); canvas.translate(transX, transY); } parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; } float transformAlpha = transformToApply.getAlpha(); if (transformAlpha < 1) { // 應用動畫資料 alpha *= transformAlpha; parent.mGroupFlags |= ViewGroup.FLAG_CLEAR_TRANSFORMATION; } }
4.屬性動畫 Property Animation
-
什麼屬性動畫
屬性動畫是android3.0官方推出的動畫功能擴充套件版,功能更加強大可以完全的替代掉之前介紹的補間動畫,主要是為了滿足補間動畫的一些不足。
-
為什麼需要屬性動畫
-
前面介紹的幀動畫和補間動畫可以很多的實現我們日常的動畫需求了,但是可以看到只能作用於view,如果操作的物件不是一個view建立的動畫就執行不了了,有個疑問為什麼需要對一個不是view的物件做動畫?有時候我們會有一些根據動畫值變更來做具體操作的需求,比如我需要計算一個顏色間值,這個值是根據計算動態變更,這種需求前面介紹的方式就滿足不了了。
-
還有一個就是補間動畫過程中是不能響應view的事件的,但是屬性動畫是可以的。
-
nineoldandroids
nineoldandroids是為了滿足3.0之前版本也能使用屬性動畫,而推出的一個相容包。
ObjectAnimator
ObjectAnimator是屬性動畫很重要的一個類,我們可以通過它的一系列靜態方法來創建出屬性動畫,它是ValueAnimator的子類。
public final class ObjectAnimator extends ValueAnimator { }
通過ofFloat方法創建出來一個animator物件,第二個是動畫的屬性名字,這個屬性名字是傳入物件裡必須要有這個屬性的get set方法,沒有的話編譯不會通過,我們這個傳入了translationX可以在view中驗證一下這個結論。
private void startObjectAnimation() { ObjectAnimator animator = ObjectAnimator.ofFloat(but, "translationX", 0, but.getWidth()); animator.setDuration(2000); animator.start();
View中對應的屬性 get set方法。
@ViewDebug.ExportedProperty(category = "drawing") public float getTranslationX() { ..... } public void setTranslationX(float translationX) { ...... }
常用的屬性
-
translationX和translationY
這兩個屬性作為一種增量控制著View物件從它佈局容器左上角座標開始的位置
-
rotation、rotationX和rotationY
這個三個屬性控制View物件圍繞支點進行2D和3D旋轉
-
scaleX和scaleY
這兩個屬性控制著View物件圍繞他的支點進行2D縮放
-
pivotX和pivotY
這兩個屬性控制著View物件的支點位置,圍繞這個支點進行旋轉和縮放變換處理。預設情況下,該支點的位置就是View物件的中心點。x和y:這兩個簡單實用的屬性,描述了View物件在它的容器中的最終位置,它是最初的左上角座標和translationX、translationY值的累積和。
-
alpha
表示View物件的alpha透明度。預設值是1(不透明),0代表完全透明(不可見)。
可以看到上面這個屬性基本上和涵蓋補間動畫的幾種動畫效果,如果傳入的物件是view中沒有的屬性怎麼辦,這個屬性動畫也可以搞定
使用自定義屬性
前面說了傳入的屬性名字,在物件中是必須有get set方法的。那麼我可以自定義一個類重寫一下自己屬性的get set方法
private static class WrapperView { private View mTarget; public WrapperView(View mTarget) { this.mTarget = mTarget; } public int getWidth() { return mTarget.getLayoutParams().width; } public void setWidth(float width) { Log.i("jinwei", " width =" + width); mTarget.getLayoutParams().width = (int) width; mTarget.requestLayout(); } }
private void startTypeObjectAnimation() { WrapperView wrapperView = new WrapperView(but); ObjectAnimator valueAnimator = ObjectAnimator.ofFloat(wrapperView, "width", 0, 2000); valueAnimator.setDuration(2000); valueAnimator.start(); }
可以看到傳入的引數是我的width欄位,它在我們的包裝類中是有get set方法的,所以符合規範編譯通過,有個疑問width屬性是如何被呼叫的,要知道內部是通過反射機制來呼叫這個width方法,具體原理這裡不做分析。
ValueAnimator
ValueAnimator是屬性動畫的核心所在,但是我們一般使用都是通過它的子類ObjectAnimator來建立動畫,ValueAnimator本身不提供任何動畫任何動畫效果,一般使用來監聽動畫數值的變化。
onAnimationUpdate會返回初始化設定的動畫數值,我們可以根據這些數值來給物件做一些動畫的變化操作。
private void valueAnimator() { ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 200); valueAnimator.setTarget(but); valueAnimator.setDuration(2000); valueAnimator.start(); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { Log.i("jinwei", animation.getAnimatedValue().toString()); } }); }
動畫監聽
一般通過AnimatorListenerAdapter這個抽象類實現方法,這樣比介面的好處是不用每個方法都實現。
private void startObjectAnimation() { WrapperView wrapperView = new WrapperView(but); ObjectAnimator animator = ObjectAnimator.ofFloat(but, "translationX", 0, but.getWidth()); animator.setDuration(2000); animator.start(); animator.setInterpolator(new AccelerateInterpolator()); animator.addListener(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) { } }); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); } });
AnimatorSet
屬性動畫也有動畫集合,可以對一列動畫進行同步執行和順序執行。
private void startAnimatorSet() { ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(but, "translationX", 300f); ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(but, "scaleX", 1f, 0f, 1f); ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(but, "scaleY", 1f, 0f, 1f); AnimatorSet set = new AnimatorSet(); set.setDuration(3000); //一起執行 set.playTogether(objectAnimator, objectAnimator1, objectAnimator2); //可以進行動畫精準順序控制 set.play(objectAnimator).before(objectAnimator1).after(objectAnimator2); set.start(); }
PropertyValuesHolder
這個類似於AnimatorSet也可以對多組動畫同步執行,但是不像AnimatorSet那樣可以進行一些順序的操作。
private void propertyValue() { PropertyValuesHolder translationX = PropertyValuesHolder.ofFloat("translationX", 500); PropertyValuesHolder scaleX = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f); PropertyValuesHolder scaleY = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f); ObjectAnimator.ofPropertyValuesHolder(but, translationX, scaleX, scaleY).setDuration(1000).start(); }
佈局中使用屬性動畫
屬性動畫和補間動畫一樣支援xml配置動畫,值得注意的是動畫檔案有規範,必須是res>animator下面的檔案才能識別。
這裡定義一個scale.xml的屬性動畫檔案
<?xml version="1.0" encoding="utf-8"?> <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" android:duration="3000" android:propertyName="scaleX" android:valueFrom="0" android:valueTo="1" android:valueType="intType"> </objectAnimator>
private void loadXmlAnimator() { Animator animator = AnimatorInflater.loadAnimator(this, R.animator.scale); animator.setTarget(but); animator.start(); }
view的animate方法
android3.0官方對view新增了animate屬性,可以直接對view進行屬性動畫操作,通過這種方式寫起來更加簡便。
private void animate() { but.animate().setDuration(2000).scaleY(0).scaleYBy(3000).start(); but.animate().setDuration(2000).translationX(0).translationXBy(3000).start(); but.animate().setDuration(2000).translationY(0).translationYBy(3000).start(); but.animate().setDuration(2000).alpha(0).alphaBy(3000).start(); }
佈局動畫
佈局動畫的作用是可以在viewGroup新增view的時候,加入一個過渡動畫效果。
private void addViewGroupAnimate() { ViewGroup viewById = findViewById(R.id.mainview); AlphaAnimation scaleAnimation = new AlphaAnimation(0, 1); scaleAnimation.setDuration(600); LayoutAnimationController lac = new LayoutAnimationController(scaleAnimation, 0.5f); viewById.setLayoutAnimation(lac); Button button = new Button(this); button.setWidth(200); button.setHeight(200); viewById.addView(button); }
插值器
插值器的主要作用是控制動畫的變化速率,比如去實現一些彈性的動畫效果,在android中自帶了幾種常用的插值器。
- AccelerateDecelerateInterpolator 在動畫開始與介紹的地方速率改變比較慢,在中間的時候加速
- AccelerateInterpolator在動畫開始的地方速率改變比較慢,然後開始加速
- AnticipateInterpolator開始的時候向後然後向前甩
- AnticipateOvershootInterpolator 開始的時候向後然後向前甩一定值後返回最後的值
- BounceInterpolator 動畫結束的時候彈起
- CycleInterpolator 動畫迴圈播放特定的次數,速率改變沿著正弦曲線
- DecelerateInterpolator 在動畫開始的地方快然後慢
- LinearInterpolator 以常量速率改變
- OvershootInterpolator 向前甩一定值後再回到原來位置
- PathInterpolator 路徑插值器
ofollow,noindex">部落格參考