日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

android动画帧率_Android动画进阶—使用开源动画库nineoldandroids

發(fā)布時間:2024/9/30 Android 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android动画帧率_Android动画进阶—使用开源动画库nineoldandroids 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

前言

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

動畫分類

View動畫:也叫漸變動畫,針對View的動畫,主要支持平移、旋轉(zhuǎn)、縮放、透明度

Drawable動畫:也叫幀動畫,主要是設(shè)置View的背景,可以以動畫的形式為View設(shè)置多張背景

對象屬性動畫(Android3.0新加入):可以對對象的屬性進行動畫而不僅僅是View,動畫默認時間間隔300ms,默認幀率10ms/幀。其可以達到的效果是:在一個時間間隔內(nèi)完成對象從一個屬性值到另一個屬性值的改變,因此,屬性動畫幾乎是無所不能的,只要對象有這個屬性,它都能實現(xiàn)動畫效果,但是屬性動畫從Android3.0才有,這就嚴重制約了屬性動畫的使用,這就是開源動畫庫nineoldandroids的作用,采用nineoldandroids,可以在3.0以前的系統(tǒng)上使用屬性動畫,nineoldandroids的網(wǎng)址是:http://nineoldandroids.com。說到屬性動畫,就不得不提到插值器(TimeInterpolator)和估值算法(TypeEvaluator),下面介紹。

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

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

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 {

public Integer evaluate(float fraction, Integer startValue, Integer endValue) {

int startInt = startValue;

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

}

}

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

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

nineoldandroids介紹

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

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

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

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

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秒內(nèi)對View的旋轉(zhuǎn)、平移、縮放和透明度都進行了改變

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:下面是個簡單的調(diào)用方式,其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實現(xiàn)的稍微復雜點的動畫

布局xml如下:

android:layout_width="match_parent"

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" />

代碼如下:

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 執(zhí)行動畫的view

* @param index view在動畫序列中的順序

* @param total 動畫序列的個數(shù)

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

}

/**

* 關(guān)閉菜單的動畫

* @param view 執(zhí)行動畫的view

* @param index view在動畫序列中的順序

* @param total 動畫序列的個數(shù)

* @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));

//為動畫加上事件監(jiān)聽,當動畫結(jié)束的時候,我們把當前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

總結(jié)

以上是生活随笔為你收集整理的android动画帧率_Android动画进阶—使用开源动画库nineoldandroids的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。