Android之API動畫學習與擴展總結

  今天寫完了一篇文章的,應該是由於篇幅太長了,發佈的時候丟了,所以搞到現在才發佈,實在抱歉,今天小馬就藉助官方 API的動畫來擴展總結下之前學習與使用過的一些知識點,風格不變,先看效果,再看代碼:

 

AnimatorSet.Builder:

      好了,效果看完了,但這篇文章主要看的不是這個簡單的效果,大家來看下文章中的註釋與解釋吧,如果有什麼不清楚的地方,一定及時留言指出批評,小馬一定會改的!

  1. package com.xiaoma.www; 
  2.  
  3. import java.util.ArrayList; 
  4.  
  5. import android.animation.Animator; 
  6. import android.animation.AnimatorListenerAdapter; 
  7. import android.animation.AnimatorSet; 
  8. import android.animation.ObjectAnimator; 
  9. import android.animation.ValueAnimator; 
  10. import android.app.Activity; 
  11. import android.content.Context; 
  12. import android.graphics.Canvas; 
  13. import android.graphics.Paint; 
  14. import android.graphics.RadialGradient; 
  15. import android.graphics.Shader; 
  16. import android.graphics.drawable.ShapeDrawable; 
  17. import android.graphics.drawable.shapes.OvalShape; 
  18. import android.os.Bundle; 
  19. import android.view.MotionEvent; 
  20. import android.view.View; 
  21. import android.view.animation.AccelerateInterpolator; 
  22. import android.view.animation.DecelerateInterpolator; 
  23. import android.widget.LinearLayout; 
  24.  
  25. /** 
  26. * @Title: BoundAnimationActivity.java 
  27. * @Package com.xiaoma.www 
  28. * @Description: 小馬API動畫學習擴展 
  29. * @author XiaoMa 
  30. */ 
  31. public class BallAnimationActivity extends Activity { 
  32.  
  33.     /**定義小球要顯示的窗口*/ 
  34.     private LinearLayout xiaoMaLayout = null ; 
  35.  
  36.     /** Called when the activity is first created. */ 
  37.     @Override 
  38.     public void onCreate(Bundle savedInstanceState) { 
  39.         super.onCreate(savedInstanceState); 
  40.         setContentView(R.layout.main); 
  41.  
  42.         init(); 
  43.     } 
  44.  
  45.     /** 
  46.      * 初始化實現 
  47.      */ 
  48.     private void init(){ 
  49.  
  50.         //定位動畫容器資源 
  51.         xiaoMaLayout = (LinearLayout)findViewById(R.id.xiaoma); 
  52.         xiaoMaLayout.addView(new BallAnimationView(this)); 
  53.     } 
  54.  
  55.     /** 
  56.     * @Title: BallAnimationActivity.java 
  57.     * @Package com.xiaoma.www 
  58.     * @Description:自定義View, 文章中我會擴展一些東西,大家要仔細看註釋哦 
  59.     * @author XiaoMa 
  60.     */ 
  61.     public class BallAnimationView extends View{ 
  62.  
  63.         //由於文章排版問題,小馬在此處稍微違背下注釋規範,多行註釋暫時用“//”來代替,大家見諒 
  64.         //這個地方大家先考慮下三個問題:(答案小馬會在後面解答) 
  65.         //1:爲什麼要用static  ? 
  66.         //2:爲什麼要用final   ? 
  67.         //3:爲什麼不用註釋中的Color類而用十六進制來定義這些顏色值,不是更方便嗎   ? 
  68.  
  69.         /**定義背景顏色更換色值*/ 
  70.         private static final int RED = 0xffFF8080
  71.         private static final int BLUE = 0xff8080FF
  72.         private static final int CYAN = 0xff80ffff
  73.         private static final int GREEN = 0xff80ff80
  74.  
  75.         /**private static final int RED1 = Color.RED; 
  76.         private static final int BLUE1 = Color.BLUE; 
  77.         private static final int CYAN1 = Color.CYAN; 
  78.         private static final int GREEN1 = Color.GREEN;*/ 
  79.  
  80.         /** 
  81.          * 這個地方解釋下吧,上面三個問題的答案:1:用static可以加快訪問速度,達到高效訪問變量; 2:用final簡單, 就是不常變;3:不用Color是因爲已經是static final了,如果用了Color.XXX的話,會長期在內存中導入一個沒必要的包,佔用內存,浪費內存資源;這個地方小馬順帶着說下,在應用中如果你經常用static來定義一些變量時,很多的變量時就會出OOM的問題啦,比如: 
  82.          * public class ClassName { 
  83.                 private static Context mContext; 
  84.             } 
  85.         上面的代碼是很噁心的,我以前就在項目中就這樣寫過,以構造方法傳遞過來,以爲寫成靜態可以方便調用對吧?其實是錯的!!!如果將Activity賦值到麼mContext的話。即使該Activity已經onDestroy,但是由於仍有對象保存它的引用,因此該Activity依然不會被釋放。擴展擴展有效避免OOM的幾種情況: 
  86.             第一,應該儘量避免static成員變量引用資源耗費過多的實例,比如Context。 
  87.             第二、Context儘量使用Application Context,因爲Application的Context的生命週期比較長,引用它不會出現內存泄露的問題。 
  88.             第三、使用WeakReference代替強引用。比如可以使用WeakReference<Context> mContextRef; 
  89.             第四、將線程的內部類,改爲靜態內部類。 
  90.             第五、在線程內部採用弱引用保存Context引用。 
  91.  
  92.          */ 
  93.  
  94.         /**聲明並初始化一個小球的容器*/ 
  95.         public final ArrayList<ShapeHolder> balls = new ArrayList<ShapeHolder>(); 
  96.  
  97.         //AnimatorSet類與AnimationSet別搞混,而且必須在3.0以上版本中才有哦... 
  98.         //此類可以根據一個特殊的順序來播放Animator對象中的動畫,而Animator則是一個 
  99.         //可以支持set結點設置動畫的詳細信息,如:開始、結束等...,set相信大家不是很陌生了吧 
  100.         //以下形式即:set結點動畫 
  101.         /**<setandroid:ordering=["together" ¦ "sequentially"]> 
  102.           <objectAnimator 
  103.               android:propertyName="string" 
  104.               android:duration="int" 
  105.               android:valueFrom="float ¦ int ¦ color" 
  106.               android:valueTo="float ¦ int ¦ color" 
  107.               android:startOffset="int" 
  108.               android:repeatCount="int" 
  109.               android:repeatMode=["repeat" ¦ "reverse"] 
  110.               android:valueType=["intType" ¦ "floatType"]/> 
  111.           <animator 
  112.               android:duration="int" 
  113.               android:valueFrom="float ¦ int ¦ color" 
  114.               android:valueTo="float ¦ int ¦ color" 
  115.               android:startOffset="int" 
  116.               android:repeatCount="int" 
  117.               android:repeatMode=["repeat" ¦ "reverse"] 
  118.               android:valueType=["intType" ¦ "floatType"]/> 
  119.           <set> 
  120.               ... 
  121.           </set> 
  122.       </set>*/ 
  123.  
  124.        /** 
  125.         * 既然在文章開頭說了要擴展很多東西的話,不僅僅是看個效果那麼簡單啦,順帶着學習回顧下動畫中的詳細屬性: 
  126.         * 四種主要的動畫類型: 
  127.           alpha        漸變透明度動畫效果 
  128.           scale        漸變尺寸伸縮動畫效果 
  129.           translate   畫面轉換位置移動動畫效果 
  130.           rotate       畫面轉移旋轉動畫效果 
  131.  
  132.              四種主要的動畫類型相對應的類: 
  133.           AlphaAnimation 漸變透明度動畫效果 
  134.           ScaleAnimation 漸變尺寸伸縮動畫效果 
  135.           TranslateAnimation 畫面轉換位置移動動畫效果 
  136.           RotateAnimation 畫面轉移旋轉動畫效果 
  137.              動畫的XML文件在工程中res/anim目錄,這個文件必須包含一個根元素,可以使<alpha><scale> <translate> <rotate> 
  138.              插值元素或者是把上面的元素都放入<set>元素組中,默認情況下,所有的動畫指令都是同時發生的,爲了讓他們按序列發生,需要設置一個 
  139.              特殊的屬性startOffset。動畫的指令定義了你想要發生什麼樣的轉換,當他們發生了,應該執行多長時間,轉換可以是連續的也可以使同時的 
  140.  
  141.              四大節點共同屬性彙總: 
  142.  
  143.                    屬性[類型]                    功能 
  144.          Duration[long]         屬性爲動畫持續時間 時間以毫秒爲單位 
  145.          fillAfter [boolean]    當設置爲true ,該動畫轉化在動畫結束後被應用 
  146.          fillBefore[boolean]    當設置爲true ,該動畫轉化在動畫開始前被應用 
  147.         */ 
  148.  
  149.         /**聲明播放動畫控制器*/ 
  150.         AnimatorSet animator = null ;  
  151.  
  152.         //這個地方大家應該發現了點什麼吧?想想爲什麼用這個構造不用下面註釋的構造? 
  153.         public BallAnimationView(Context context) { //方式一 
  154.             super(context); 
  155.             //上一篇講ObjectAnimator,這個地方大家現在應該知道ValueAnimator是幹嗎的了吧?吼吼 
  156.             ValueAnimator backAnim = ObjectAnimator.ofInt(this"backgroundColor", RED,BLUE,CYAN,GREEN); 
  157.             //設置自動更換背景色的時間爲每隔2秒更換一次 
  158.             backAnim.setDuration(2000); 
  159.             backAnim.setRepeatCount(ValueAnimator.INFINITE); 
  160.             backAnim.setRepeatMode(ValueAnimator.REVERSE); 
  161.             backAnim.start(); 
  162.         } 
  163.  
  164.         /**public BallAnimationView(Context context, AttributeSet attrs) { //方式二 
  165.             super(context, attrs); 
  166.             // TODO Auto-generated constructor stub 
  167.         }*/ 
  168.  
  169.         /** 
  170.          * 這個地方給出上面選擇構造方法時是爲什麼用第一個不用第二個構造方法的原因: 
  171.          * 一:如果是用純代碼的方式加載自定義的控制到而已中時用第一種方式, 
  172.          * 二:如果是XML文件加載的方式使用自定義控件到佈局中是用第二種方式, 
  173.          */ 
  174.  
  175.         @Override 
  176.         protected void onDraw(Canvas canvas) { 
  177.             for (int i = 0; i < balls.size(); ++i) { 
  178.                 ShapeHolder shapeHolder = balls.get(i); 
  179.                 canvas.save(); 
  180.                 //這個地方的translate()這個方法,如果朋友們要深究的話可以自行學習下,不想的話只知道怎麼用就行了... 
  181.                 //矩陣轉換在這不多說了,因爲我懂的矩陣不多,只記下這個小點:Matrix的基本操作包括:+、*。Matrix的乘法不滿足交換律,也就是說A*B ≠B*A。 
  182.                 canvas.translate(shapeHolder.getX(), shapeHolder.getY()); 
  183.                 shapeHolder.getShape().draw(canvas); 
  184.                 canvas.restore(); //重置畫布 
  185.             } 
  186.             super.onDraw(canvas); 
  187.         } 
  188.  
  189.         /** 
  190.          * 監聽觸屏事件,以此來播放動畫 
  191.          * */ 
  192.         @Override 
  193.         public boolean onTouchEvent(MotionEvent event) { 
  194.             if(event.getAction() != MotionEvent.ACTION_DOWN 
  195.                && event.getAction() != MotionEvent.ACTION_MOVE){ 
  196.                 return false
  197.             } 
  198.             ShapeHolder newBall = addBall(event.getX(), event.getY()); 
  199.  
  200.             // Bouncing animation with squash and stretch 
  201.             float startY = newBall.getY(); 
  202.             float endY = getHeight() - 50f; 
  203.             //獲取的這個高度是當前View的高度 
  204.             float h = (float)getHeight(); 
  205.             float eventY = event.getY(); 
  206.             int duration = (int)(500 * ((h - eventY)/h)); 
  207.             ValueAnimator bounceAnim = ObjectAnimator.ofFloat(newBall, "y", startY, endY); 
  208.             bounceAnim.setDuration(duration); 
  209.             //這個地方使用到插值器,順帶講下幾種插值器 
  210.             //打過人家門窗玻璃的人都知道,石頭剛扔出時的狀態是:先快先慢,以下講到使用的插值器就是這個道理, 
  211.             //所以說有些事還是小時候練成的哦!! 
  212.  
  213.             /**accelerate_decelerate_interpolator 
  214.                                     加速-減速 動畫插入器 
  215.  
  216.             accelerate_interpolator 
  217.                                     加速-動畫插入器 
  218.  
  219.             decelerate_interpolator 
  220.                                      減速- 動畫插入器*/ 
  221.  
  222.             //下面這些實現細節的代碼小馬就不一條條加註釋 了,只加下比較特殊的地方 
  223.             bounceAnim.setInterpolator(new AccelerateInterpolator()); 
  224.             ValueAnimator squashAnim1 = ObjectAnimator.ofFloat(newBall, "x", newBall.getX(), 
  225.                     newBall.getX() - 25f); 
  226.             squashAnim1.setDuration(duration/4); 
  227.             squashAnim1.setRepeatCount(1); 
  228.             squashAnim1.setRepeatMode(ValueAnimator.REVERSE); 
  229.             squashAnim1.setInterpolator(new DecelerateInterpolator()); 
  230.             ValueAnimator squashAnim2 = ObjectAnimator.ofFloat(newBall, "width", newBall.getWidth(), 
  231.                     newBall.getWidth() + 50); 
  232.             squashAnim2.setDuration(duration/4); 
  233.             squashAnim2.setRepeatCount(1); 
  234.             squashAnim2.setRepeatMode(ValueAnimator.REVERSE); 
  235.             squashAnim2.setInterpolator(new DecelerateInterpolator()); 
  236.             ValueAnimator stretchAnim1 = ObjectAnimator.ofFloat(newBall, "y", endY, 
  237.                     endY + 25f); 
  238.             stretchAnim1.setDuration(duration/4); 
  239.             stretchAnim1.setRepeatCount(1); 
  240.             stretchAnim1.setInterpolator(new DecelerateInterpolator()); 
  241.             stretchAnim1.setRepeatMode(ValueAnimator.REVERSE); 
  242.             ValueAnimator stretchAnim2 = ObjectAnimator.ofFloat(newBall, "height"
  243.                     newBall.getHeight(), newBall.getHeight() - 25); 
  244.             stretchAnim2.setDuration(duration/4); 
  245.             stretchAnim2.setRepeatCount(1); 
  246.             stretchAnim2.setInterpolator(new DecelerateInterpolator()); 
  247.             stretchAnim2.setRepeatMode(ValueAnimator.REVERSE); 
  248.             ValueAnimator bounceBackAnim = ObjectAnimator.ofFloat(newBall, "y", endY, 
  249.                     startY); 
  250.             bounceBackAnim.setDuration(duration); 
  251.             bounceBackAnim.setInterpolator(new DecelerateInterpolator()); 
  252.             // Sequence the down/squash&stretch/up animations 
  253.             AnimatorSet bouncer = new AnimatorSet(); 
  254.  
  255.             //下面三個之前、之後、同一時間來添加動畫,此處什麼意思,我就不一句句翻譯了,大家直接看官方解釋就可以了,截圖在動畫效果三後一張: 
  256.             //如果大家想詳細瞭解學習AnimatorSet.Builder的話可以看下下面官方這個鏈接... 
  257.             //http://developer.android.com/reference/android/animation/AnimatorSet.Builder.html 
  258.             bouncer.play(bounceAnim).before(squashAnim1); 
  259.             bouncer.play(squashAnim1).with(squashAnim2); 
  260.             bouncer.play(squashAnim1).with(stretchAnim1); 
  261.             bouncer.play(squashAnim1).with(stretchAnim2); 
  262.             bouncer.play(bounceBackAnim).after(stretchAnim2); 
  263.  
  264.             // 看到alpha漸變了吧?當小球反彈到最後時變爲全透明,並從容器中remove透明的小球 
  265.             ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f); 
  266.             fadeAnim.setDuration(250); 
  267.             fadeAnim.addListener(new AnimatorListenerAdapter() { 
  268.                 @Override 
  269.                 public void onAnimationEnd(Animator animation) { 
  270.                     balls.remove(((ObjectAnimator)animation).getTarget()); 
  271.  
  272.                 } 
  273.             }); 
  274.  
  275.             // 按順序排列好其它小球的動畫 
  276.             AnimatorSet animatorSet = new AnimatorSet(); 
  277.             animatorSet.play(bouncer).before(fadeAnim); 
  278.  
  279.             animatorSet.start(); 
  280.             return true
  281.         } 
  282.  
  283.         /*** 
  284.          * 將小球添加到容器中方法實現 
  285.          * @param x 
  286.          * @param y 
  287.          * @return 添加的小球對象 
  288.          */ 
  289.         private ShapeHolder addBall(float x, float y) { 
  290.             OvalShape circle = new OvalShape(); 
  291.             circle.resize(50f, 50f); 
  292.             ShapeDrawable drawable = new ShapeDrawable(circle); 
  293.             ShapeHolder shapeHolder = new ShapeHolder(drawable); 
  294.             shapeHolder.setX(x - 25f); 
  295.             shapeHolder.setY(y - 25f); 
  296.             //隨機取RGB三種顏色 
  297.             int red = (int)(Math.random() * 255); 
  298.             int green = (int)(Math.random() * 255); 
  299.             int blue = (int)(Math.random() * 255); 
  300.             //下面是:得到一個16進製表示的顏色,相當於:0xff(red的16進制值)(green的16進制值)(blue的16進制值) 
  301.             //比如 0xff886644 88 = red 66 = green 44 = blue這樣的,第一次見到這個東西,大家記得記下哦 
  302.             int color = 0xff000000 ¦ red << 16 ¦ green << 8 ¦ blue; 
  303.             Paint paint = drawable.getPaint(); //得到畫筆 
  304.             int darkColor = 0xff000000 ¦ red/4 << 16 ¦ green/4 << 8 ¦ blue/4
  305.             //用給定的圓心、半徑、顏色和展示模式來繪製小球,這裏使用的模式是:平鋪模式: 
  306.             //展示模式有三種分別是:平鋪模式、 平鋪模式非重疊模式、 非重疊模式 
  307.             RadialGradient gradient = new RadialGradient(37.5f, 12.5f, 
  308.                     50f, color, darkColor, Shader.TileMode.CLAMP); 
  309.             //設置畫筆要繪製的圖片 
  310.             paint.setShader(gradient); 
  311.             //設置畫筆開 
  312.             shapeHolder.setPaint(paint); 
  313.             balls.add(shapeHolder); 
  314.             return shapeHolder; 
  315.         } 
  316.  
  317.     } 

    主控制類看完了,下面來看下這個簡單的輔助類,如果下:

  1. package com.xiaoma.www; 
  2.  
  3. import android.graphics.Paint; 
  4. import android.graphics.RadialGradient; 
  5. import android.graphics.drawable.ShapeDrawable; 
  6. import android.graphics.drawable.shapes.Shape; 
  7.  
  8. /** 
  9. * @Title: ShapeHolder.java 
  10. * @Package com.xiaoma.www 
  11. * @Description: 動畫輔助類 
  12. * @author XiaoMa 
  13. */ 
  14. public class ShapeHolder { 
  15.     private float x = 0, y = 0
  16.     private ShapeDrawable shape; 
  17.     private int color; 
  18.     private RadialGradient gradient; 
  19.     private float alpha = 1f; 
  20.     private Paint paint; 
  21.  
  22.     public void setPaint(Paint value) { 
  23.         paint = value; 
  24.     } 
  25.     public Paint getPaint() { 
  26.         return paint; 
  27.     } 
  28.  
  29.     public void setX(float value) { 
  30.         x = value; 
  31.     } 
  32.     public float getX() { 
  33.         return x; 
  34.     } 
  35.     public void setY(float value) { 
  36.         y = value; 
  37.     } 
  38.     public float getY() { 
  39.         return y; 
  40.     } 
  41.     public void setShape(ShapeDrawable value) { 
  42.         shape = value; 
  43.     } 
  44.     public ShapeDrawable getShape() { 
  45.         return shape; 
  46.     } 
  47.     public int getColor() { 
  48.         return color; 
  49.     } 
  50.     public void setColor(int value) { 
  51.         shape.getPaint().setColor(value); 
  52.         color = value; 
  53.     } 
  54.     public void setGradient(RadialGradient value) { 
  55.         gradient = value; 
  56.     } 
  57.     public RadialGradient getGradient() { 
  58.         return gradient; 
  59.     } 
  60.  
  61.     public void setAlpha(float alpha) { 
  62.         this.alpha = alpha; 
  63.         shape.setAlpha((int)((alpha * 255f) + .5f)); 
  64.     } 
  65.  
  66.     public float getWidth() { 
  67.         return shape.getShape().getWidth(); 
  68.     } 
  69.     public void setWidth(float width) { 
  70.         Shape s = shape.getShape(); 
  71.         s.resize(width, s.getHeight()); 
  72.     } 
  73.  
  74.     public float getHeight() { 
  75.         return shape.getShape().getHeight(); 
  76.     } 
  77.     public void setHeight(float height) { 
  78.         Shape s = shape.getShape(); 
  79.         s.resize(s.getWidth(), height); 
  80.     } 
  81.  
  82.     public ShapeHolder(ShapeDrawable s) { 
  83.         shape = s; 
  84.     } 
         好啦,學習擴展知識看完了,如果大家有好的建議或者需要什麼地方需要小馬整理總結的,記得留言提出,看到留言會第一時間回覆並總結整理出來的,謝謝啦,每天進步一點點,也算一種進步,今天不小心丟了裏面好多東西,發佈有點不給力,不過沒事,之後小馬的文章會越來越全面,越來全詳細的,今天就寫到這了,大家加油,把工作當成自己的興趣,才能獲得源源不斷的動力,加油加油!!!一起學習一起進步,這就是編程的快樂!加油…..O_O!
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章