1. 程式人生 > >Android動畫進階—使用開源動畫庫nineoldandroids

Android動畫進階—使用開源動畫庫nineoldandroids

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow

也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!

                轉載請註明出處:http://blog.csdn.net/singwhatiwanna/article/details/17639987

前言

Android系統支援原生動畫,這為應用開發者開發絢麗的介面提供了極大的方便,有時候動畫是很必要的,當你想做一個滑動的特效的時候,如果苦思冥想都搞不定,那麼你可以考慮下動畫,說不定動畫輕易就搞定了。下面再簡單回顧下Android中的動畫,本文後面會介紹一個稍微複雜點的動畫,先上效果圖


動畫分類

View動畫:也叫漸變動畫,針對View的動畫,主要支援平移、旋轉、縮放、透明度

Drawable動畫:也叫幀動畫,主要是設定View的背景,可以以動畫的形式為View設定多張背景

物件屬性動畫(Android3.0新加入):可以對物件的屬性進行動畫而不僅僅是View,動畫預設時間間隔300ms,預設幀率10ms/幀。其可以達到的效果是:在一個時間間隔內完成物件從一個屬性值到另一個屬性值的改變,因此,屬性動畫幾乎是無所不能的,只要物件有這個屬性,它都能實現動畫效果,但是屬性動畫從Android3.0才有,這就嚴重製約了屬性動畫的使用,這就是開源動畫庫nineoldandroids的作用,採用nineoldandroids,可以在3.0以前的系統上使用屬性動畫,nineoldandroids的網址是:

http://nineoldandroids.com。說到屬性動畫,就不得不提到插值器(TimeInterpolator)和估值演算法(TypeEvaluator),下面介紹。

TimeInterpolator和TypeEvaluator

TimeInterpolator中文翻譯為時間插值器,它的作用是根據時間流逝的百分比來計算出當前屬性值改變的百分比,系統預置的有LinearInterpolator(線性插值器:勻速動畫)、AccelerateDecelerateInterpolator(加速減速插值器:動畫兩頭慢中間快)和DecelerateInterpolator(減速插值器:動畫越來越慢)等;TypeEvaluator的中文翻譯為型別估值演算法,它的作用是根據當前屬性改變的百分比來計算改變後的屬性值,系統預置的有IntEvaluator(針對整型屬性)、FloatEvaluator(針對浮點型屬性)和ArgbEvaluator(針對Color屬性)。可能這麼說還有點晦澀,沒關係,下面給出一個例項就很好理解了。


看上述動畫,很顯然上述動畫是一個勻速動畫,其採用了線性插值器和整型估值演算法,在40ms內,View的x屬性實現從0到40的變換,由於動畫的預設重新整理率為10ms/幀,所以該動畫將分5幀進行,我們來考慮第三幀(x=20 t=20ms),當時間t=20ms的時候,時間流逝的百分比是0.5 (20/40=0.5),意味這現在時間過了一半,那x應該改變多少呢,這個就由插值器和估值演算法來確定。拿線性插值器來說,當時間流逝一半的時候,x的變換也應該是一半,即x的改變是0.5,為什麼呢?因為它是線性插值器,是實現勻速動畫的,下面看它的原始碼:

public class LinearInterpolator implements Interpolator {    public LinearInterpolator() {    }        public LinearInterpolator(Context context, AttributeSet attrs) {    }        public float getInterpolation(float input) {        return input;    }}

很顯然,線性插值器的返回值和輸入值一樣,因此插值器返回的值是0.5,這意味著x的改變是0.5,這個時候插值器的工作就完成了。

具體x變成了什麼值,這個需要估值演算法來確定,我們來看看整型估值演算法的原始碼:

public class IntEvaluator implements TypeEvaluator<Integer> {    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {        int startInt = startValue;        return (int)(startInt + fraction * (endValue - startInt));    }}

上述演算法很簡單,evaluate的三個引數分別表示:估值小數、開始值和結束值,對應於我們的例子就分別是:0.5,0,40。根據上述演算法,整型估值返回給我們的結果是20,這就是(x=20 t=20ms)的由來。

說明:屬性動畫要求該屬性有set方法和get方法(可選);插值器和估值演算法除了系統提供的外,我們還可以自定義,實現方式也很簡單,因為插值器和估值演算法都是一個介面,且內部都只有一個方法,我們只要派生一個類實現介面就可以了,然後你就可以做出千奇百怪的動畫效果。具體一點就是:自定義插值器需要實現Interpolator或者TimeInterpolator,自定義估值演算法需要實現TypeEvaluator。還有就是如果你對其他型別(非int、float、color)做動畫,你必須要自定義型別估值演算法。

nineoldandroids介紹

其功能和android.animation.*中的類的功能完全一致,使用方法完全一樣,只要我們用nineoldandroids來編寫動畫,就可以在所有的Android系統上執行。比較常用的幾個動畫類是:ValueAnimator、ObjectAnimator和AnimatorSet,其中ObjectAnimator繼承自ValueAnimator,AnimatorSet是動畫集,可以定義一組動畫。使用起來也是及其簡單的,下面舉幾個小栗子。

栗子1:改變一個物件(myObject)的 translationY屬性,讓其沿著Y軸向上平移一段距離:它的高度,該動畫在預設時間內完成,動畫的完成時間是可以定義的,想要更靈活的效果我們還可以定義插值器和估值演算法,但是一般來說我們不需要自定義,系統已經預置了一些,能夠滿足常用的動畫。

ObjectAnimator.ofFloat(myObject, "translationY", -myObject.getHeight()).start();

栗子2:改變一個物件的背景色屬性,典型的情形是改變View的背景色,下面的動畫可以讓背景色在3秒內實現從0xFFFF8080到0xFF8080FF的漸變,並且動畫會無限迴圈而且會有反轉的效果

ValueAnimator colorAnim = ObjectAnimator.ofInt(this, "backgroundColor", /*Red*/0xFFFF8080, /*Blue*/0xFF8080FF);colorAnim.setDuration(3000);colorAnim.setEvaluator(new ArgbEvaluator());colorAnim.setRepeatCount(ValueAnimator.INFINITE);colorAnim.setRepeatMode(ValueAnimator.REVERSE);colorAnim.start();

栗子3:動畫集合,5秒內對View的旋轉、平移、縮放和透明度都進行了改變

AnimatorSet set = new AnimatorSet();set.playTogether(    ObjectAnimator.ofFloat(myView, "rotationX", 0, 360),    ObjectAnimator.ofFloat(myView, "rotationY", 0, 180),    ObjectAnimator.ofFloat(myView, "rotation", 0, -90),    ObjectAnimator.ofFloat(myView, "translationX", 0, 90),    ObjectAnimator.ofFloat(myView, "translationY", 0, 90),    ObjectAnimator.ofFloat(myView, "scaleX", 1, 1.5f),    ObjectAnimator.ofFloat(myView, "scaleY", 1, 0.5f),    ObjectAnimator.ofFloat(myView, "alpha", 1, 0.25f, 1));set.setDuration(5 * 1000).start();

栗子4:下面是個簡單的呼叫方式,其animate方法是nineoldandroids特有的

Button myButton = (Button)findViewById(R.id.myButton);//Note: in order to use the ViewPropertyAnimator like this add the following import://  import static com.nineoldandroids.view.ViewPropertyAnimator.animate;animate(myButton).setDuration(2000).rotationYBy(720).x(100).y(100);

栗子5:一個採用nineoldandroids實現的稍微複雜點的動畫

佈局xml如下:

<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent" >    <Button        android:id="@+id/menu"        style="@style/MenuStyle"        android:background="@drawable/menu" />    <Button        android:id="@+id/item1"        style="@style/MenuItemStyle"        android:background="@drawable/circle1"        android:visibility="gone" />    <Button        android:id="@+id/item2"        style="@style/MenuItemStyle"        android:background="@drawable/circle2"        android:visibility="gone" />    <Button        android:id="@+id/item3"        style="@style/MenuItemStyle"        android:background="@drawable/circle3"        android:visibility="gone" />    <Button        android:id="@+id/item4"        style="@style/MenuItemStyle"        android:background="@drawable/circle4"        android:visibility="gone" />    <Button        android:id="@+id/item5"        style="@style/MenuItemStyle"        android:background="@drawable/circle5"        android:visibility="gone" /></FrameLayout>

程式碼如下:

public class MainActivity extends Activity implements OnClickListener {    private static final String TAG = "MainActivity";    private Button mMenuButton;    private Button mItemButton1;    private Button mItemButton2;    private Button mItemButton3;    private Button mItemButton4;    private Button mItemButton5;    private boolean mIsMenuOpen = false;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initView();    }    @TargetApi(Build.VERSION_CODES.HONEYCOMB)    private void initView() {        mMenuButton = (Button) findViewById(R.id.menu);        mMenuButton.setOnClickListener(this);        mItemButton1 = (Button) findViewById(R.id.item1);        mItemButton1.setOnClickListener(this);        mItemButton2 = (Button) findViewById(R.id.item2);        mItemButton2.setOnClickListener(this);        mItemButton3 = (Button) findViewById(R.id.item3);        mItemButton3.setOnClickListener(this);        mItemButton4 = (Button) findViewById(R.id.item4);        mItemButton4.setOnClickListener(this);        mItemButton5 = (Button) findViewById(R.id.item5);        mItemButton5.setOnClickListener(this);    }    @Override    public boolean onCreateOptionsMenu(Menu menu) {        mMenuButton.performClick();        getMenuInflater().inflate(R.menu.main, menu);        return false;    }    @Override    public void onClick(View v) {        if (v == mMenuButton) {            if (!mIsMenuOpen) {                mIsMenuOpen = true;                doAnimateOpen(mItemButton1, 0, 5, 300);                doAnimateOpen(mItemButton2, 1, 5, 300);                doAnimateOpen(mItemButton3, 2, 5, 300);                doAnimateOpen(mItemButton4, 3, 5, 300);                doAnimateOpen(mItemButton5, 4, 5, 300);            } else {                mIsMenuOpen = false;                doAnimateClose(mItemButton1, 0, 5, 300);                doAnimateClose(mItemButton2, 1, 5, 300);                doAnimateClose(mItemButton3, 2, 5, 300);                doAnimateClose(mItemButton4, 3, 5, 300);                doAnimateClose(mItemButton5, 4, 5, 300);            }        } else {            Toast.makeText(this, "你點選了" + v, Toast.LENGTH_SHORT).show();        }    }    /**     * 開啟選單的動畫     * @param view 執行動畫的view     * @param index view在動畫序列中的順序     * @param total 動畫序列的個數     * @param radius 動畫半徑     */    private void doAnimateOpen(View view, int index, int total, int radius) {        if (view.getVisibility() != View.VISIBLE) {            view.setVisibility(View.VISIBLE);        }        double degree = Math.PI * index / ((total - 1) * 2);        int translationX = (int) (radius * Math.cos(degree));        int translationY = (int) (radius * Math.sin(degree));        Log.d(TAG, String.format("degree=%f, translationX=%d, translationY=%d",                degree, translationX, translationY));        AnimatorSet set = new AnimatorSet();        //包含平移、縮放和透明度動畫        set.playTogether(                ObjectAnimator.ofFloat(view, "translationX", 0, translationX),                ObjectAnimator.ofFloat(view, "translationY", 0, translationY),                ObjectAnimator.ofFloat(view, "scaleX", 0f, 1f),                ObjectAnimator.ofFloat(view, "scaleY", 0f, 1f),                ObjectAnimator.ofFloat(view, "alpha", 0f, 1));        //動畫週期為500ms        set.setDuration(1 * 500).start();    }    /**     * 關閉選單的動畫     * @param view 執行動畫的view     * @param index view在動畫序列中的順序     * @param total 動畫序列的個數     * @param radius 動畫半徑     */    private void doAnimateClose(final View view, int index, int total,            int radius) {        if (view.getVisibility() != View.VISIBLE) {            view.setVisibility(View.VISIBLE);        }        double degree = Math.PI * index / ((total - 1) * 2);        int translationX = (int) (radius * Math.cos(degree));        int translationY = (int) (radius * Math.sin(degree));        Log.d(TAG, String.format("degree=%f, translationX=%d, translationY=%d",                degree, translationX, translationY));        AnimatorSet set = new AnimatorSet();      //包含平移、縮放和透明度動畫        set.playTogether(                ObjectAnimator.ofFloat(view, "translationX", translationX, 0),                ObjectAnimator.ofFloat(view, "translationY", translationY, 0),                ObjectAnimator.ofFloat(view, "scaleX", 1f, 0f),                ObjectAnimator.ofFloat(view, "scaleY", 1f, 0f),                ObjectAnimator.ofFloat(view, "alpha", 1f, 0f));        //為動畫加上事件監聽,當動畫結束的時候,我們把當前view隱藏        set.addListener(new AnimatorListener() {            @Override            public void onAnimationStart(Animator animator) {            }            @Override            public void onAnimationRepeat(Animator animator) {            }            @Override            public void onAnimationEnd(Animator animator) {                view.setVisibility(View.GONE);            }            @Override            public void onAnimationCancel(Animator animator) {            }        });        set.setDuration(1 * 500).start();    }}
程式碼下載: http://download.csdn.net/detail/singwhatiwanna/6782865           

給我老師的人工智慧教程打call!http://blog.csdn.net/jiangjunshow

這裡寫圖片描述 你好! 這是你第一次使用 **Markdown編輯器** 所展示的歡迎頁。如果你想學習如何使用Markdown編輯器, 可以仔細閱讀這篇文章,瞭解一下Markdown的基本語法知識。

新的改變

我們對Markdown編輯器進行了一些功能拓展與語法支援,除了標準的Markdown編輯器功能,我們增加了如下幾點新功能,幫助你用它寫部落格:

  1. 全新的介面設計 ,將會帶來全新的寫作體驗;
  2. 在創作中心設定你喜愛的程式碼高亮樣式,Markdown 將程式碼片顯示選擇的高亮樣式 進行展示;
  3. 增加了 圖片拖拽 功能,你可以將本地的圖片直接拖拽到編輯區域直接展示;
  4. 全新的 KaTeX數學公式 語法;
  5. 增加了支援甘特圖的mermaid語法1 功能;
  6. 增加了 多螢幕編輯 Markdown文章功能;
  7. 增加了 焦點寫作模式、預覽模式、簡潔寫作模式、左右區域同步滾輪設定 等功能,功能按鈕位於編輯區域與預覽區域中間;
  8. 增加了 檢查列表 功能。

功能快捷鍵

撤銷:Ctrl/Command + Z
重做:Ctrl/Command + Y
加粗:Ctrl/Command + B
斜體:Ctrl/Command + I
標題:Ctrl/Command + Shift + H
無序列表:Ctrl/Command + Shift + U
有序列表:Ctrl/Command + Shift + O
檢查列表:Ctrl/Command + Shift + C
插入程式碼:Ctrl/Command + Shift + K
插入連結:Ctrl/Command + Shift + L
插入圖片:Ctrl/Command + Shift + G

合理的建立標題,有助於目錄的生成

直接輸入1次#,並按下space後,將生成1級標題。
輸入2次#,並按下space後,將生成2級標題。
以此類推,我們支援6級標題。有助於使用TOC語法後生成一個完美的目錄。

如何改變文字的樣式

強調文字 強調文字

加粗文字 加粗文字

標記文字

刪除文字

引用文字

H2O is是液體。

210 運算結果是 1024.

插入連結與圖片

連結: link.

圖片: Alt

帶尺寸的圖片: Alt

當然,我們為了讓使用者更加便捷,我們增加了圖片拖拽功能。

如何插入一段漂亮的程式碼片

部落格設定頁面,選擇一款你喜歡的程式碼片高亮樣式,下面展示同樣高亮的 程式碼片.

// An highlighted block var foo = 'bar'; 

生成一個適合你的列表

  • 專案
    • 專案
      • 專案
  1. 專案1
  2. 專案2
  3. 專案3
  • 計劃任務
  • 完成任務

建立一個表格

一個簡單的表格是這麼建立的:

專案 Value
電腦 $1600
手機 $12
導管 $1

設定內容居中、居左、居右

使用:---------:居中
使用:----------居左
使用----------:居右

第一列 第二列 第三列
第一列文字居中 第二列文字居右 第三列文字居左

SmartyPants

SmartyPants將ASCII標點字元轉換為“智慧”印刷標點HTML實體。例如:

TYPE ASCII HTML
Single backticks 'Isn't this fun?' ‘Isn’t this fun?’
Quotes "Isn't this fun?" “Isn’t this fun?”
Dashes -- is en-dash, --- is em-dash – is en-dash, — is em-dash

建立一個自定義列表

Markdown
Text-to- HTML conversion tool
Authors
John
Luke

如何建立一個註腳

一個具有註腳的文字。2

註釋也是必不可少的

Markdown將文字轉換為 HTML

KaTeX數學公式

您可以使用渲染LaTeX數學表示式 KaTeX:

Gamma公式展示 Γ ( n ) = ( n 1 ) ! n N \Gamma(n) = (n-1)!\quad\forall n\in\mathbb N 是通過尤拉積分

Γ ( z ) = 0 t z 1 e t d t &ThinSpace; . \Gamma(z) = \int_0^\infty t^{z-1}e^{-t}dt\,.

你可以找到更多關於的資訊 LaTeX 數學表示式here.

新的甘特圖功能,豐富你的文章

gantt
        dateFormat  YYYY-MM-DD
        title Adding GANTT diagram functionality to mermaid
        section 現有任務
        已完成               :done,    des1, 2014-01-06,2014-01-08
        進行中               :active,  des2, 2014-01-09, 3d
        計劃一               :         des3, after des2, 5d
        計劃二               :         des4, after des3, 5d
  • 關於 甘特圖 語法,參考 這兒,

UML 圖表

可以使用UML圖表進行渲染。 Mermaid. 例如下面產生的一個序列圖::

這將產生一個流程圖。:

  • 關於 Mermaid 語法,參考 這兒,

FLowchart流程圖

我們依舊會支援flowchart的流程圖:

  • 關於 Flowchart流程圖 語法,參考 這兒.

匯出與匯入

匯出

如果你想嘗試使用此編輯器, 你可以在此篇文章任意編輯。當你完成了一篇文章的寫作, 在上方工具欄找到 文章匯出 ,生成一個.md檔案或者.html檔案進行本地儲存。

匯入

如果你想載入一篇你寫過的.md檔案或者.html檔案,在上方工具欄可以選擇匯入功能進行對應副檔名的檔案匯入,
繼續你的創作。


  1. mermaid語法說明 ↩︎

  2. 註腳的解釋 ↩︎