Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android動畫使用開源動畫庫nineoldandroids

Android動畫使用開源動畫庫nineoldandroids

編輯:關於Android編程

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,為什麼呢?因為它是線性插值器,是實現勻速動畫的,下面看它的源碼:

publicclassLinearInterpolatorimplementsInterpolator{

publicLinearInterpolator(){

}

publicLinearInterpolator(Contextcontext,AttributeSetattrs){

}

publicfloatgetInterpolation(floatinput){

returninput;

}

}

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

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

publicclassIntEvaluatorimplementsTypeEvaluator{

publicIntegerevaluate(floatfraction,IntegerstartValue,IntegerendValue){

intstartInt=startValue;

return(int)(startInt+fraction*(endValue-startInt));

}

}

[java]view plaincopy

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

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

[java]view plaincopy

ValueAnimatorcolorAnim=ObjectAnimator.ofInt(this,"backgroundColor",/*Red*/0xFFFF8080,/*Blue*/0xFF8080FF);

colorAnim.setDuration(3000);

colorAnim.setEvaluator(newArgbEvaluator());

colorAnim.setRepeatCount(ValueAnimator.INFINITE);

colorAnim.setRepeatMode(ValueAnimator.REVERSE);

colorAnim.start();

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

[java]view plaincopy

AnimatorSetset=newAnimatorSet();

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特有的

[java]view plaincopy

ButtonmyButton=(Button)findViewById(R.id.myButton);

//Note:inordertousetheViewPropertyAnimatorlikethisaddthefollowingimport:

//importstaticcom.nineoldandroids.view.ViewPropertyAnimator.animate;

animate(myButton).setDuration(2000).rotationYBy(720).x(100).y(100);

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

布局xml如下:

[html]view plaincopy

android:layout_height="match_parent">

android:id="@+id/menu"

style="@style/MenuStyle"

android:background="@drawable/menu"/>

android:id="@+id/item1"

style="@style/MenuItemStyle"

android:background="@drawable/circle1"

android:visibility="gone"/>

android:id="@+id/item2"

style="@style/MenuItemStyle"

android:background="@drawable/circle2"

android:visibility="gone"/>

android:id="@+id/item3"

style="@style/MenuItemStyle"

android:background="@drawable/circle3"

android:visibility="gone"/>

android:id="@+id/item4"

style="@style/MenuItemStyle"

android:background="@drawable/circle4"

android:visibility="gone"/>

android:id="@+id/item5"

style="@style/MenuItemStyle"

android:background="@drawable/circle5"

android:visibility="gone"/>

代碼如下:

[java]view plaincopy

publicclassMainActivityextendsActivityimplementsOnClickListener{

privatestaticfinalStringTAG="MainActivity";

privateButtonmMenuButton;

privateButtonmItemButton1;

privateButtonmItemButton2;

privateButtonmItemButton3;

privateButtonmItemButton4;

privateButtonmItemButton5;

privatebooleanmIsMenuOpen=false;

@Override

protectedvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

initView();

}

@TargetApi(Build.VERSION_CODES.HONEYCOMB)

privatevoidinitView(){

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

publicbooleanonCreateOptionsMenu(Menumenu){

mMenuButton.performClick();

getMenuInflater().inflate(R.menu.main,menu);

returnfalse;

}

@Override

publicvoidonClick(Viewv){

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();

}

}

/**

*打開菜單的動畫

*@paramview執行動畫的view

*@paramindexview在動畫序列中的順序

*@paramtotal動畫序列的個數

*@paramradius動畫半徑

*/

privatevoiddoAnimateOpen(Viewview,intindex,inttotal,intradius){

if(view.getVisibility()!=View.VISIBLE){

view.setVisibility(View.VISIBLE);

}

doubledegree=Math.PI*index/((total-1)*2);

inttranslationX=(int)(radius*Math.cos(degree));

inttranslationY=(int)(radius*Math.sin(degree));

Log.d(TAG,String.format("degree=%f,translationX=%d,translationY=%d",

degree,translationX,translationY));

AnimatorSetset=newAnimatorSet();

//包含平移、縮放和透明度動畫

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();

}

/**

*關閉菜單的動畫

*@paramview執行動畫的view

*@paramindexview在動畫序列中的順序

*@paramtotal動畫序列的個數

*@paramradius動畫半徑

*/

privatevoiddoAnimateClose(finalViewview,intindex,inttotal,

intradius){

if(view.getVisibility()!=View.VISIBLE){

view.setVisibility(View.VISIBLE);

}

doubledegree=Math.PI*index/((total-1)*2);

inttranslationX=(int)(radius*Math.cos(degree));

inttranslationY=(int)(radius*Math.sin(degree));

Log.d(TAG,String.format("degree=%f,translationX=%d,translationY=%d",

degree,translationX,translationY));

AnimatorSetset=newAnimatorSet();

//包含平移、縮放和透明度動畫

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(newAnimatorListener(){

@Override

publicvoidonAnimationStart(Animatoranimator){

}

@Override

publicvoidonAnimationRepeat(Animatoranimator){

}

@Override

publicvoidonAnimationEnd(Animatoranimator){

view.setVisibility(View.GONE);

}

@Override

publicvoidonAnimationCancel(Animatoranimator){

}

});

set.setDuration(1*500).start();

}


  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved