文章主要內(nèi)容來源《Android開發(fā)藝術(shù)探索》,部分內(nèi)容來源網(wǎng)上的文章,文中會(huì)有鏈接。
Android系統(tǒng)提供了兩個(gè)動(dòng)畫框架:屬性動(dòng)畫框架和View動(dòng)畫框架。 兩個(gè)動(dòng)畫框架都是可行的選項(xiàng),但是屬性動(dòng)畫框架通常是首選的使用方法,因?yàn)樗`活,并提供更多的功能。 除了這兩個(gè)框架,還可以使用Drawable動(dòng)畫(即逐幀動(dòng)畫,AnimationDrawable),它允許你加載Drawable資源并逐幀地顯示它們。
View動(dòng)畫框架(補(bǔ)間動(dòng)畫)
View動(dòng)畫框架中一共提供了AlphaAnimation(透明度動(dòng)畫)、RotateAnimation(旋轉(zhuǎn)動(dòng)畫)、ScaleAnimation(縮放動(dòng)畫)、TranslateAnimation(平移動(dòng)畫)四種類型的補(bǔ)間動(dòng)畫;并且View動(dòng)畫框架還提供了動(dòng)畫集合類(AnimationSet),通過動(dòng)畫集合類(AnimationSet)可以將多個(gè)補(bǔ)間動(dòng)畫以組合的形式顯示出來。補(bǔ)間動(dòng)畫的實(shí)現(xiàn),一般會(huì)采用xml文件的形式,那樣代碼會(huì)更容易書寫和閱讀,同時(shí)也更容易復(fù)用。屬性動(dòng)畫框架
與屬性動(dòng)畫相比View動(dòng)畫存在一個(gè)缺陷,View動(dòng)畫改變的只是View的顯示,而沒有改變View的響應(yīng)區(qū)域,并且View動(dòng)畫只能對(duì)View做四種類型的補(bǔ)間動(dòng)畫。因此Google在Android3.0(API級(jí)別11)及其后續(xù)版本中添加了屬性動(dòng)畫框架,從名稱中就可以知道只要某個(gè)類具有屬性(即該類含有某個(gè)字段的set和get方法),那么屬性動(dòng)畫框架就可以對(duì)該類的對(duì)象進(jìn)行動(dòng)畫操作(其實(shí)就是通過反射技術(shù)來獲取和執(zhí)行屬性的get,set方法),同樣屬性動(dòng)畫框架還提供了動(dòng)畫集合類(AnimatorSet),通過動(dòng)畫集合類(AnimatorSet)可以將多個(gè)屬性動(dòng)畫以組合的形式顯示出來。作者:ForeverCy
鏈接:http://www.jianshu.com/p/b117c974deaf
來源:簡(jiǎn)書
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。
View動(dòng)畫的四種變換效果對(duì)應(yīng)著Animation的四個(gè)子類:TranslateAnimation、ScaleAnimation、RotateAnimation、AlphaAnimation。四種動(dòng)畫可以用這四個(gè)類通過代碼實(shí)現(xiàn),也可以使用XML文件來定義。建議使用XML來定義動(dòng)畫,因?yàn)閄ML格式可讀性好而且方便復(fù)用。
名稱 | 標(biāo)簽 | 子類 |
---|---|---|
平移動(dòng)畫 | TranslateAnimation | |
縮放動(dòng)畫 | ScaleAnimation | |
選中動(dòng)畫 | RotateAnimation | |
透明度動(dòng)畫 | AlphaAnimation |
<set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="" android:shareInterpolator="true|false"> <translate android:fromXDelta="" android:toXDelta="" android:fromYDelta="" android:toYDelta="" /> <scale android:fromXScale="" android:toXScale="" android:fromYScale="" android:toYScale="" android:pivotX="" android:pivotY="" /> <rotate android:fromDegrees="" android:toDegrees="" android:pivotX="" android:pivotY="" /> <alpha android:fromAlpha="" android:toAlpha="" /> <set> <!--set嵌套set--> </set></set>
View動(dòng)畫可以是單個(gè)動(dòng)畫,也可以由一系列動(dòng)畫組成,使用
android:interpolator表示動(dòng)畫集合所使用的插值器,插值器影響動(dòng)畫的速度,比如非勻速動(dòng)畫就需要通過插值器來控制動(dòng)畫的播放過程。這個(gè)屬性可以不指定,默認(rèn)是@android:anim/accelerate_decelerate_interpolator,即加速減速插值器。
android:shareInterpolator表示集合中的動(dòng)畫是否和集合共享同一個(gè)插值器。如果集合不指定插值器,那么子動(dòng)畫就需要單獨(dú)指定所需要的插值器或者使用默認(rèn)值。
android:fromXDelta x的起始值
android:toXDelta x的結(jié)束值
android:fromYDelta y的起始值
android:toYDelta y的結(jié)束值
android:fromXScale 水平方向縮放的起始值
android:toXScale 水平方向縮放的結(jié)束值
android:fromYScale 豎直方向縮放的起始值
android:toYScale 豎直方向縮放的結(jié)束值
android:pivotX 縮放的軸點(diǎn)的x坐標(biāo)
android:pivotY 縮放的軸點(diǎn)的y坐標(biāo)
android:fromDegrees 旋轉(zhuǎn)開始的角度
android:toDegrees 旋轉(zhuǎn)結(jié)束的角度
android:pivotX 旋轉(zhuǎn)的軸點(diǎn)的x坐標(biāo)
android:pivotY 選中的軸點(diǎn)的y坐標(biāo)
android:fromAlpha 透明度的起始值
android:toAlpha 透明度的結(jié)束值
android:duration 動(dòng)畫的持續(xù)時(shí)間
android:fillBefore 動(dòng)畫結(jié)束后是否回到執(zhí)行前的位置
android:fillAfter 動(dòng)畫結(jié)束后是否停留在結(jié)束位置
android:interpolator 動(dòng)畫使用的插值器
android:startOffset 動(dòng)畫執(zhí)行之前的等待時(shí)間
android:repeatCount 動(dòng)畫重復(fù)執(zhí)行的次數(shù)
xml屬性都有對(duì)應(yīng)的set方法
首先編寫動(dòng)畫xml文件test_anim.xml
Button mButton = (Button)findViewById(R.id.button);Animation animation = AnimationUtils.loadAnimation(context, R.anim.test_anim);mButton.startAnimation(animation);
也可以通過代碼實(shí)現(xiàn)
AlphaAnimation animation = new AlphaAnimation(0, 1);animation.setDuration(300);mButton.startAnimation(animation);
使用setAnimationListener方法可以給動(dòng)畫添加過程監(jiān)聽。
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android" android:delay="150" android:animationOrder="normal" android:animation="@anim/anim_item"/>
android:delay 子元素開始動(dòng)畫的時(shí)間延遲
android:animationOrder 子元素動(dòng)畫的順序。有normal(順序)、reverse(逆向)、random(隨機(jī))三種順序。
android:animation 子元素入場(chǎng)的具體動(dòng)畫
<translate xmlns:android="http://schemas.android.com/apk/res/android" android:fromXDelta="500" android:toXDelta="0"/>
<ListView android:id="@ id/list" android:layout_width="match_parent" android:layout_height="match_parent" android:layoutAnimation="@anim/anim_layout" />
除了通過xml中指定layoutAnimation屬性,也可以通過LayoutAnimationController來實(shí)現(xiàn):
Animation animation = AnimationUtils.loadAnimation(context, R.anim.anim_item);LayoutAnimationController controller = new LayoutAnimationController(animation);controller.setDelay(0.5f);controller.setOrder(LayoutAnimationController.ORDER_NORMAL);listView.setLayoutAnimation(controller);
使用overridePendingTransition(int enterAnim, int exitAnim)方法實(shí)現(xiàn)Activity的切換動(dòng)畫,這個(gè)方法必須在startActivity()或者finish()之后調(diào)用才能生效。
Fragment也可以添加切換動(dòng)畫,通過FragmentTransaction中的setCustomAnimations()方法實(shí)現(xiàn)。
幀動(dòng)畫的標(biāo)簽是
示例代碼
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false"> <item android:drawable="@drawable/img1" android:duration="500"/> <item android:drawable="@drawable/img2" android:duration="500"/> <item android:drawable="@drawable/img3" android:duration="500"/></animation-list>
Button mButton = (Button)findViewById(R.id.button1);mButton.setBackgroundResource(R.drawable.frame_animation);AnimationDrawable drawable = (AnimationDrawable)mButton.getBackground();drawable.start();
注意幀動(dòng)畫容易引起OOM。
屬性動(dòng)畫從 API 11 才有,屬性動(dòng)畫可以對(duì)任意對(duì)象的屬性進(jìn)行動(dòng)畫而不僅僅是View,達(dá)到的效果是:在一個(gè)時(shí)間間隔內(nèi)完成對(duì)象從一個(gè)屬性值到另一個(gè)屬性值的改變。屬性動(dòng)畫常用的動(dòng)畫類:ValueAnimator、ObjectAnimator、AnimatorSet。ObjectAnimator繼承自ValueAnimator,AnimatorSet是動(dòng)畫集合。
屬性動(dòng)畫也有對(duì)應(yīng)的xml標(biāo)簽,但是建議使用代碼來實(shí)現(xiàn)屬性動(dòng)畫,因?yàn)槭褂么a比xml簡(jiǎn)單。而且很多時(shí)候一個(gè)屬性的起始值無法提前確定。
ObjectAnimator.ofFloat(myObject, "translationY", -myObject.getHeight()).start();
ValueAnimator anim = ObjectAnimator.ofInt(myObject, "backgroundColor",0xFFFF8080,0xFF8080FF);anim.setDuration(3000);anim.setEvaluator(new ArgbEvaluator());anim.setRepeatCount(ValueAnimator.INFINITE);anim.setRepeatMode(ValueAnimator.REVERSE);anim.start();
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();
上面代碼用到一個(gè)主要的方法
ObjectAnimator.ofFloat(target, propertyName, values...);
target 是動(dòng)畫目標(biāo),任何對(duì)象,不一定必須是View
propertyName 是屬性名字
values 是可變參數(shù), 從v1變化到v2到vn。。。
例子:
mIv是一個(gè)imageView
//alpha 從0 到1 的動(dòng)畫
ObjectAnimator.ofFloat(mIv, "alpha", 0f,1f)
.setDuration(500)
.start();
如果要實(shí)現(xiàn)其他效果,修改propertyName和values就行了。
屬性動(dòng)畫的原理就是通過反射,以動(dòng)畫的效果多次調(diào)用set方法來改變屬性值的。所以,使用屬性動(dòng)畫時(shí),相應(yīng)的對(duì)象屬性必須有set方法,get方法可以沒有,但是如果使用動(dòng)畫的時(shí)候沒有傳遞初始值,就必須提供get方法,因?yàn)橄到y(tǒng)要通過get方法獲取屬性的默認(rèn)初始值。
alpha 透明度
rotation z軸旋轉(zhuǎn)
rotationX x軸旋轉(zhuǎn)
rotationY y軸旋轉(zhuǎn)
translationX x水平偏移
translationY y水平偏移
ScaleX x軸縮放
ScaleY y軸縮放
插值器(TimeInterpolator/Interpolator)用來修飾動(dòng)畫效果,定義動(dòng)畫的變化規(guī)率(變化趨勢(shì)),比如平移動(dòng)畫,可以勻速平移也可以加速平移,這個(gè)由插值器決定。
估值器(Evaluator)用來決定具體的數(shù)值變化,比如(勻)加速平移時(shí),“加速度”是多少由估值器決定。
插值器TimeInterpolator和Interpolator,后者是繼承前者的接口。
TimeInterpolator接口是屬性動(dòng)畫中新增的,用于兼容Interpolator接口,這使得所有過去的Interpolator實(shí)現(xiàn)類都可以直接在屬性動(dòng)畫使用。
出自:http://blog.csdn.net/carson_ho/article/details/72863901
IntEvaluator 以整型的形式從初始值到結(jié)束值 進(jìn)行過渡
FloatEvaluator 以浮點(diǎn)型的形式從初始值到結(jié)束值 進(jìn)行過渡
ArgbEvaluator 以Argb類型的形式從初始值到結(jié)束值 進(jìn)行過渡
如果系統(tǒng)內(nèi)置的插值器和估值器無法滿足需求,也可以自定義。
View動(dòng)畫的插值器實(shí)現(xiàn)Interpolator接口,View動(dòng)畫沒有估值器
屬性動(dòng)畫的插值器實(shí)現(xiàn)實(shí)現(xiàn)TimeInterpolator接口,估值器實(shí)現(xiàn)TypeEvaluator接口
自定義插值器和估值器參考系統(tǒng)內(nèi)置的插值器和估值器即可。
以下摘自http://blog.csdn.net/carson_ho/article/details/72863901
實(shí)現(xiàn)Interpolator接口自定義插值器的說明(TimeInterpolator接口相同)
public interface Interpolator { // 內(nèi)部只有一個(gè)方法 float getInterpolation(float input) { // 參數(shù)說明 // input值值變化范圍是0-1,且隨著動(dòng)畫進(jìn)度(0% - 100% )均勻變化 // 即動(dòng)畫開始時(shí),input值 = 0;動(dòng)畫結(jié)束時(shí)input = 1 // 而中間的值則是隨著動(dòng)畫的進(jìn)度(0% - 100%)在0到1之間均勻增加 ...// 插值器的計(jì)算邏輯 return xxx; // 返回的值就是用于估值器繼續(xù)計(jì)算的fraction值 }}
實(shí)現(xiàn)TypeEvaluator接口自定義估值器的說明
public interface TypeEvaluator { public Object evaluate(float fraction, Object startValue, Object endValue) { // 參數(shù)說明 // fraction:插值器getInterpolation()的返回值 // startValue:動(dòng)畫的初始值 // endValue:動(dòng)畫的結(jié)束值 ....// 估值器的計(jì)算邏輯 return xxx; // 賦給動(dòng)畫屬性的具體數(shù)值 // 使用反射機(jī)制改變屬性變化 // 特別注意 // 插值器的input值 和 估值器fraction有什么關(guān)系呢? // 答:input的值決定了fraction的值:input值經(jīng)過計(jì)算后傳入到插值器的getInterpolation() // 然后通過實(shí)現(xiàn)getInterpolation()中的邏輯算法,根據(jù)input值來計(jì)算出一個(gè)返回值,而這個(gè)返回值就是fraction了 } }
View動(dòng)畫和屬性動(dòng)畫都可以使用插值器,估值器只有屬性動(dòng)畫可以用。
插值器用法
// 步驟1:創(chuàng)建需要設(shè)置動(dòng)畫的視圖ViewButton mButton = (Button) findViewById(R.id.Button);// 步驟2:創(chuàng)建透明度動(dòng)畫的對(duì)象 & 設(shè)置動(dòng)畫效果Animation alphaAnimation = new AlphaAnimation(1,0); alphaAnimation.setDuration(3000);// 步驟3:創(chuàng)建對(duì)應(yīng)的插值器類對(duì)象Interpolator overshootInterpolator = new OvershootInterpolator();// 步驟4:給動(dòng)畫設(shè)置插值器alphaAnimation.setInterpolator(overshootInterpolator);// 步驟5:播放動(dòng)畫mButton.startAnimation(alphaAnimation);
估值器用法
// 在第3個(gè)參數(shù)中傳入對(duì)應(yīng)估值器類的對(duì)象ObjectAnimator anim = ObjectAnimator.ofObject(myView2, "height", new Evaluator(),1,3);
有兩個(gè)監(jiān)聽接口AnimatorListener和AnimatorUpdateListener。AnimatorListener和View動(dòng)畫的AnimationListener類似,可以監(jiān)聽動(dòng)畫的開始、結(jié)束等過程。AnimatorUpdateListener可以監(jiān)聽動(dòng)畫的每一幀變化,動(dòng)畫每變化一幀,接口里的方法被調(diào)用一次。
private void performAnimate(final View button, final int start, final int end) { ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100); valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { //持有一個(gè)IntEvaluator對(duì)象,方便下面估值的時(shí)候使用 private IntEvaluator mIntEvaluator = new IntEvaluator(); @Override public void onAnimationUpdate(ValueAnimator animator) { //獲得當(dāng)前動(dòng)畫的進(jìn)度值,整型1-100之間 int currentValue = (int) animator.getAnimatedValue(); //獲得當(dāng)前進(jìn)度占整個(gè)動(dòng)畫過程的比例,浮點(diǎn)型,0-1之間 float fraction = animator.getAnimatedFraction(); //直接調(diào)用整型估值器,通過比例計(jì)算出寬度,然后設(shè)給Button button.getLayoutParams().width = mIntEvaluator.evaluate(fraction, start, end); button.requestLayout(); } }); valueAnimator.setDuration(5000).start();}@Overridepublic void onClick(View v) { if (v == mButton) { performAnimate(mButton, mButton.getWidth(), 500); }}
View動(dòng)畫可以設(shè)置ViewGroup的子View的出場(chǎng)動(dòng)畫,屬性動(dòng)畫可以為ViewGroup的子View的顯示和隱藏設(shè)置過渡動(dòng)畫。出場(chǎng)動(dòng)畫文中已經(jīng)介紹,屬性動(dòng)畫實(shí)現(xiàn)的過度動(dòng)畫詳細(xì)見ForeverCy的文章Android中的View動(dòng)畫和屬性動(dòng)畫 中的相關(guān)部分。
來源:https://www.icode9.com/content-4-267701.html聯(lián)系客服