Android 動(dòng)畫(huà)(View動(dòng)畫(huà),幀動(dòng)畫(huà),屬性動(dòng)畫(huà))詳細(xì)介紹
0. 前言
Android動(dòng)畫(huà)是面試的時(shí)候經(jīng)常被問(wèn)到的話題。我們都知道Android動(dòng)畫(huà)分為三類:View動(dòng)畫(huà)、幀動(dòng)畫(huà)和屬性動(dòng)畫(huà)。
先對(duì)這三種動(dòng)畫(huà)做一個(gè)概述:
View動(dòng)畫(huà)是一種漸進(jìn)式動(dòng)畫(huà),通過(guò)圖像的平移、縮放、旋轉(zhuǎn)和透明度等各種漸進(jìn)式變換完成動(dòng)畫(huà)效果。
幀動(dòng)畫(huà)是通過(guò)不停的切換圖片實(shí)現(xiàn)動(dòng)畫(huà)效果。
屬性動(dòng)畫(huà)是不停的改變對(duì)象的屬性來(lái)實(shí)現(xiàn)動(dòng)畫(huà)效果。本文原創(chuàng),轉(zhuǎn)載請(qǐng)注明出處:
http://blog.csdn.net/seu_calvin/article/details/52724655
1. View動(dòng)畫(huà)
1.1 系統(tǒng)提供的四種View動(dòng)畫(huà)(補(bǔ)間動(dòng)畫(huà))
View動(dòng)畫(huà)可以在res/anim/name.xml文件里進(jìn)行配置,四種View動(dòng)畫(huà)的漸變式變換分別對(duì)應(yīng)<translate>、<scale>、<rotate>、<alpha>四個(gè)標(biāo)簽,動(dòng)畫(huà)集合可以使用<set>標(biāo)簽。xml的各個(gè)動(dòng)畫(huà)屬性比較簡(jiǎn)單,這里就不再貼實(shí)例代碼了。只需要注意如何應(yīng)用配置好的xml文件來(lái)啟動(dòng)動(dòng)畫(huà)即可:
view.startAnimation(AnimationUtils.loadAnimation(this,R.anim.myanimation));
這些當(dāng)然也可以在Java代碼里進(jìn)行配置,也比較簡(jiǎn)單,這里寫(xiě)了一個(gè)示例代碼:
splash = (RelativeLayout)findViewById(R.id.splash);
//旋轉(zhuǎn)動(dòng)畫(huà)
RotateAnimation rotateAnimation = new RotateAnimation(0,360,
Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
rotateAnimation.setDuration(2000);
rotateAnimation.setFillAfter(true);
//縮放動(dòng)畫(huà)
ScaleAnimation scaleAnimation = new ScaleAnimation(0,1,0,1,
Animation.RELATIVE_TO_SELF,0.5f,Animation.RELATIVE_TO_SELF,0.5f);
scaleAnimation.setDuration(2000);
scaleAnimation.setFillAfter(true);
//漸變動(dòng)畫(huà)
AlphaAnimation alphaAnimation = new AlphaAnimation(0.2f,1.0f);
alphaAnimation.setDuration(2000);
alphaAnimation.setFillAfter(true);
//平移動(dòng)畫(huà)
TranslateAnimation translateAnimation = newTranslateAnimation (0,0,100,100);
translateAnimation.setDuration(2000);
translateAnimation.setFillAfter(true);
//動(dòng)畫(huà)集合
AnimationSet animationSet = new AnimationSet(true);
animationSet.addAnimation(rotateAnimation);
animationSet.addAnimation(scaleAnimation);
animationSet.addAnimation(alphaAnimation);
animationSet.addAnimation(translateAnimation);
//啟動(dòng)動(dòng)畫(huà)
plash.startAnimation(animationSet);
1.2 自定義View動(dòng)畫(huà)
自定義動(dòng)畫(huà)實(shí)際應(yīng)用中比較少見(jiàn),因此這里只做簡(jiǎn)單介紹。
完成自定義動(dòng)畫(huà)需要繼承Animation類,并重寫(xiě)其initialize()以及applyTransformation()。
前者用于一些初始化的操作,后者用于進(jìn)行矩陣變換。
1.3 為ViewGroup的所有子元素設(shè)置動(dòng)畫(huà)
上面1.1,1.2都是給View設(shè)置動(dòng)畫(huà)效果,Android同樣提供了為ViewGroup設(shè)置
android:layoutAnimation=”@anim/layout_anim”來(lái)達(dá)到給ViewGroup中所有子元素設(shè)置動(dòng)畫(huà)的目的。下面給出相關(guān)代碼:
//res/anim/anim/layout_anim.xml <layoutAnimation xmlns:android=” http://schemas.android.com/apk/res/android” android:delay=”0.1” //動(dòng)畫(huà)延遲時(shí)間為0.1*T,本例為100ms android:animationOrder=”normal” //子元素的播放動(dòng)畫(huà)順序?yàn)轫樞?,也有reverse以及random android: animation=” @anim/layout_anim_item”/> //res/anim/anim/layout_anim_item.xml <?xml version=”1.0” encoding=”utf-8”?> <set xmlns:android=”http://schemas.android.com/apk/res/android” animation:duration=”200” //每個(gè)子元素的動(dòng)畫(huà)周期T animation:interpolator=”@android:anim/accelerate_ interpolator” //指定插值器 animation:shareInterpolator=”true”> //表示所有子元素共享該插值器 <alpha android:fromAlpha=”0.2” android: toAlpha =”1.0”/> <translate android:fromXDelta=”100” android: toXDelta =”0”/> </set>
1.4 為Activity切換設(shè)置動(dòng)畫(huà)
估計(jì)大家也都用過(guò),在startActivity()之后使用,使Activity切換時(shí)達(dá)到一個(gè)平移的動(dòng)畫(huà)效果:
overridePendingTransition(R.anim.tran_in,R.anim.tran_out);
//res/anim/tran_in <?xml version="1.0" encoding="utf-8"?> <translate xmlns:android="http://schemas.android.com/apk/res/android" android:duration="500" //表示從屏幕100%的位置開(kāi)始,因此tran_out當(dāng)然是toXDelta="-100%p",其他不變 android:fromXDelta="100%p" android:fromYDelta="0" android:toXDelta="0" android:toYDelta="0" > </translate>
2. 幀動(dòng)畫(huà)
上面也提到了,幀動(dòng)畫(huà)就是不停的切換圖片實(shí)現(xiàn)動(dòng)畫(huà)效果。很明顯容易OOM,所以使用幀動(dòng)畫(huà)要注意圖片大小。
幀動(dòng)畫(huà)的使用也很簡(jiǎn)單,使用示例如下:
//res/drawable/myanimation.xml <?xml version=”1.0” encoding=”utf-8”?> <animation-list xmlns:android=”http://schemas.android.com/apk/res/android” animation:oneshot=”false” > //false為循環(huán)播放,true為類似于View動(dòng)畫(huà)的setFillAfter效果 <item android: drawable =”@ drawable/ drawable 1” android:duration=” 200”> <item android: drawable =”@ drawable/ drawable 2” android:duration=” 200”> </animation-list> //在代碼里加載動(dòng)畫(huà)設(shè)置并啟動(dòng)動(dòng)畫(huà) view.setBackgroundResource(R.drawable.myanimation.xml); (AnimationDrawable)view.getBackground.start();
3. 屬性動(dòng)畫(huà)
View動(dòng)畫(huà)的那四種效果有很明顯的缺點(diǎn),繪制出來(lái)的效果其實(shí)并沒(méi)有真正改變View的屬性,即left、top、right和bottom的值,只是系統(tǒng)臨時(shí)繪制的結(jié)果。這樣View的點(diǎn)擊位置并沒(méi)有發(fā)生變化。針對(duì)這個(gè)問(wèn)題,從Android3.0開(kāi)始屬性動(dòng)畫(huà)應(yīng)運(yùn)而生。
屬性動(dòng)畫(huà)本質(zhì)是通過(guò)改變新增的屬性(如平移translationX/Y、縮放scaleX/Y、旋轉(zhuǎn)rotationX/Y等)并刷新屏幕來(lái)實(shí)現(xiàn)動(dòng)畫(huà)效果,并且實(shí)現(xiàn)點(diǎn)擊位置的實(shí)時(shí)改變。但是屬性動(dòng)畫(huà)仍然不會(huì)修改原始的上下左右四個(gè)值。最后需要注意的是,屬性動(dòng)畫(huà)不止用于View,還可以用于任何對(duì)象。
下面介紹與屬性動(dòng)畫(huà)相關(guān)的類和方法:
3.1 setTranslationX方法
該方法直接更改view屬性的方法,因?yàn)橛袝r(shí)候不需要使用動(dòng)畫(huà)效果。
view.setTranslationX(x);//3.0以后 ViewHelper.setTranslationX(view,x);//3.0以前通過(guò)NineOldAndroid庫(kù)實(shí)現(xiàn)
3.2 ValueAnimator類
ValueAnimator只定義和執(zhí)行動(dòng)畫(huà)流程,并沒(méi)有直接操作屬性值的邏輯,需要添加動(dòng)畫(huà)更新的監(jiān)聽(tīng),并在onAnimationUpdate()中執(zhí)行自定義的動(dòng)畫(huà)邏輯。
[java] view plain copy 在CODE上查看代碼片派生到我的代碼片
ValueAnimator animator = ValueAnimator.ofInt(1, 100); //定義動(dòng)畫(huà),相當(dāng)于1秒內(nèi)數(shù)100個(gè)數(shù)
animator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation){
float fraction = animation.getAnimatedFraction();//動(dòng)畫(huà)進(jìn)度值0-1
//整型估值器幫我們計(jì)算了start+(end-strat)*fraction,并設(shè)置給控件的寬度
view.getLayoutParams().width = new IntEvaluator().evaluate(fraction,start,end) //不需要set方法
view.requestLayout();
}
});
animator.setDuration(1000).start();
3.3 ObjectAnimator類
ObjectAnimator繼承自ValueAnimator,它允許直接改變view的屬性,下面通過(guò)一個(gè)例子介紹。
//x軸方向縮放的例子 ObjectAnimator animator = ObjectAnimator.ofFloat(view,”scaleX”,2.0f); animator.setDuration(1000); animator.setStartDelay(1000); animator.start();
大多數(shù)的情況使用ObjectAnimator就足夠了,因?yàn)樗挥孟馰alueAnimator那樣自己寫(xiě)動(dòng)畫(huà)更新的邏輯,但是ObjectAnimator有一定的限制——它需要目標(biāo)屬性提供指定的處理方法(譬如提供get/set方法),這是因?yàn)镺bjectAnimator的原理是不停的調(diào)用set方法更新屬性值,并且如果我們沒(méi)有傳遞初始值,系統(tǒng)會(huì)直接調(diào)用get方法獲取值。而上面3.2中介紹過(guò)的ValueAnimator則不直接操作屬性值,所以要操作對(duì)象的屬性可以不需要se/get方法,你完全可以通過(guò)當(dāng)前動(dòng)畫(huà)的計(jì)算去修改任何屬性。
針對(duì)這個(gè)問(wèn)題,官方推薦我們用一個(gè)類包裝原始對(duì)象,間接為其提供get/set方法,實(shí)現(xiàn)起來(lái)很簡(jiǎn)單,實(shí)例如下:
ViewWrapper wrapper = new ViewWrapper(view);
ObjectAnimator.ofInt(view,”width”,200).setDuration(1000).start();
private static class ViewWrapper{
private View myView;
public ViewWrapper(View view){
myView = view;
}
public int getWidth(){
return myView.getLayoutParams().width;
}
public int setWidth(int width){
myView.getLayoutParams().width = width;
myView.requestLayout();
}
}
3.4 ViewPropertyAnimation類
ViewPropertyAnimation是NineOldAndroid庫(kù)中的類,簡(jiǎn)化了ObjectAnimator類的操作,并且NineOldAndroid庫(kù)兼容了3.0以前的Android版本。下面經(jīng)過(guò)一個(gè)例子介紹。
//x軸方向縮放的例子,效果同3.3 ViewPropertyAnimation.animate(view).scaleX(2.0f).setDuration(1000) .setInterpolator(new OvershootInterpolator()) .setStartDelay(1000).start();
3.5 AnimationSet類
動(dòng)畫(huà)集合,提供把多個(gè)動(dòng)畫(huà)組合成一個(gè)組合的機(jī)制,并可設(shè)置動(dòng)畫(huà)的時(shí)序關(guān)系,如同時(shí)播放、順序播放或延遲播放。具體使用方法比較簡(jiǎn)單,如下所示:
ObjectAnimator objectAnimator1= ObjectAnimator.ofFloat(view, "alpha", 1.0f, 0f); ObjectAnimator objectAnimator2= ObjectAnimator.ofFloat(view, "translationY", 0f, 30f); ObjectAnimator objectAnimator3= ObjectAnimator.ofFloat(view, "translationX", 0f, 30f); AnimatorSet animatorSet = new AnimatorSet(); animatorSet.setDuration(5000); animatorSet.setInterpolator(new LinearInterpolator()); // animatorSet.playTogether(objectAnimator1, objectAnimator2. objectAnimator3); //三個(gè)動(dòng)畫(huà)同時(shí)執(zhí)行 // 12同時(shí)執(zhí)行,3接著執(zhí)行 animatorSet.play(objectAnimator1).with(objectAnimator2); animatorSet.play(objectAnimator3).after(objectAnimator2); animatorSet.start();
4. 插值器總結(jié)
4.1 系統(tǒng)已經(jīng)提供給我們的插值器
各種插值器都是實(shí)現(xiàn)了Interpolator接口,下面來(lái)看一下系統(tǒng)已經(jīng)提供給我們直接使用的插值器。

4.2 自定義插值器
Interpolator都實(shí)現(xiàn)了Interpolator接口,而Interpolator接口又繼承自TimeInterpolator,TimeInterpolator接口定義了一個(gè)由系統(tǒng)調(diào)用的getInterpolation(float input)方法,其中參數(shù)input代表動(dòng)畫(huà)完成進(jìn)度,在0和1之間。我們自定義插值器只需要實(shí)現(xiàn)Interpolator接口并覆寫(xiě)getInterpolation()方法即可實(shí)現(xiàn)自定義的動(dòng)畫(huà)效果。
如下就是一個(gè)動(dòng)畫(huà)始末速率較慢、中間加速的AccelerateDecelerateInterpolator插值器:
public class AccelerateDecelerateInterpolator extends BaseInterpolator
implements NativeInterpolatorFactory {
......
public float getInterpolation(float input) {
return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}
......
}
5. 動(dòng)畫(huà)監(jiān)聽(tīng)器
我們?cè)谄綍r(shí)開(kāi)發(fā)過(guò)程中,經(jīng)常要監(jiān)聽(tīng)動(dòng)畫(huà)完成的時(shí)機(jī)以繼續(xù)業(yè)務(wù)邏輯,那么我們可以通過(guò)給動(dòng)畫(huà)集合設(shè)置AnimationListener監(jiān)聽(tīng)器來(lái)實(shí)現(xiàn)。分別可以監(jiān)聽(tīng)動(dòng)畫(huà)開(kāi)始、結(jié)束、取消以及重復(fù)播放。
//監(jiān)聽(tīng)動(dòng)畫(huà)完成
animationSet.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {}
@Override
public void onAnimationEnd(Animation animation) {}
@Override
public void onAnimationRepeat(Animation animation) {}
@Override
public void onAnimationCancel(Animation animation) {}
});
最后若想監(jiān)聽(tīng)動(dòng)畫(huà)中每一幀的回調(diào),我們可以設(shè)置AnimatorUpdateListener監(jiān)聽(tīng)器并重寫(xiě)其onAnimationUpdate()方法即可。
至此關(guān)于Android動(dòng)畫(huà)的知識(shí)總結(jié)完畢。
感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
- Android動(dòng)畫(huà)之逐幀動(dòng)畫(huà)(Frame Animation)實(shí)例詳解
- Android逐幀動(dòng)畫(huà)實(shí)現(xiàn)代碼
- Android 使用幀動(dòng)畫(huà)內(nèi)存溢出解決方案
- Android之仿美團(tuán)加載數(shù)據(jù)幀動(dòng)畫(huà)
- Android動(dòng)畫(huà)之逐幀動(dòng)畫(huà)(Frame Animation)基礎(chǔ)學(xué)習(xí)
- Android幀動(dòng)畫(huà)、補(bǔ)間動(dòng)畫(huà)、屬性動(dòng)畫(huà)用法詳解
- Android編程之簡(jiǎn)單逐幀動(dòng)畫(huà)Frame的實(shí)現(xiàn)方法
- Android 幀動(dòng)畫(huà)的實(shí)例詳解
- Android 逐幀動(dòng)畫(huà)創(chuàng)建實(shí)例詳解
- Android Studio實(shí)現(xiàn)幀動(dòng)畫(huà)
相關(guān)文章
Android程序開(kāi)發(fā)之ListView實(shí)現(xiàn)橫向滾動(dòng)(帶表頭與固定列)
這篇文章主要介紹了Android程序開(kāi)發(fā)之ListView實(shí)現(xiàn)橫向滾動(dòng)(帶表頭與固定列)的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-07-07
Android7.0 MTK設(shè)置默認(rèn)桌面
這篇文章主要為大家詳細(xì)介紹了Android7.0 MTK設(shè)置默認(rèn)桌面,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-07-07
android實(shí)現(xiàn)切換日期左右無(wú)限滑動(dòng)效果
本篇內(nèi)容給大家分享了android開(kāi)發(fā)時(shí)候?qū)崿F(xiàn)自定義的日期無(wú)限左右滑動(dòng)效果以及控件使用的技巧。2017-11-11
Android用 Mob 實(shí)現(xiàn)發(fā)送短信驗(yàn)證碼實(shí)例
這篇文章主要介紹了Android用 Mob 實(shí)現(xiàn)發(fā)送短信驗(yàn)證碼實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-06-06
Flutter插件開(kāi)發(fā)之HmsScanKit實(shí)現(xiàn)示例詳解
這篇文章主要為大家介紹了Flutter插件開(kāi)發(fā)之HmsScanKit實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11
Android Flutter制作交錯(cuò)動(dòng)畫(huà)的示例代碼
這篇文章我們將用Flutter實(shí)現(xiàn)一個(gè)交錯(cuò)動(dòng)畫(huà)的應(yīng)用實(shí)例,我們讓輪子在草地滾動(dòng)著前進(jìn),而且還能粘上“綠色的草”,感興趣的可以動(dòng)手嘗試一下2022-06-06

