7.1 View 動畫
View 動畫對應(yīng)這 Animation 的四個子類:
名稱 | 標(biāo)簽 | 子類 | 效果 |
---|---|---|---|
平移動畫 | <translate> | TranslateAnimation | 移動 View |
縮放動畫 | <scale> | ScaleAnimation | 放大或縮小 View |
旋轉(zhuǎn)動畫 | <rotate> | RotateAnimation | 旋轉(zhuǎn) View |
透明度動畫 | <alpha> | AlphaAnimation | 改變 View 的透明度 |
<set> 標(biāo)簽表示動畫集合区转,對應(yīng) AnimationSet 類函似,它可以包含若干個動畫,并且內(nèi)部也可以嵌套動畫集合店乐。
android:interpolator
表示動畫集合采用的插值器艰躺,影響動畫的速度,可以不指定為勻速眨八。android:shareInterpolator
表示集合中的動畫是否和集合共享同一個插值器腺兴。如果集合不指定插值器,那么自動化就需要單獨指定所需的插值器或者使用默認(rèn)值廉侧。
<translate>標(biāo)簽表示平移動畫含长,對呀 TranslateAnimation 類,它可以使一個 View 在水平和豎直方向完成平移動畫效果伏穆。
android:fromXDelta:表示 x 的起始值,比如 0纷纫;
android:toXDelta:表示 x 的結(jié)束值枕扫,比如 100;
android:fromYDelta:表示 y 的起始值辱魁;
android:toYDelta:表示 y 的結(jié)束值;
<scale>標(biāo)簽表示縮放動畫,對應(yīng) ScaleAnimation雌团,它可以使 View 具有放大或者縮小的動畫效果檐蚜。
android:fromXScale:水平方向的起始值,比如 0.5漩仙;
android:toXScale:水平方向縮放的結(jié)束值,比如 1.2;
android:pivotX:縮放軸點的x坐標(biāo)蝌箍,它會影響縮放的效果;
android:pivotY:縮放軸點的y坐標(biāo)暴心,它會影響縮放的效果妓盲;
android:toXScale:水平方向縮放的結(jié)束值,比如1.2专普;
android:toYScale:豎直方向縮放的起始值悯衬;
<rotate>標(biāo)簽表示旋轉(zhuǎn)動畫,對應(yīng)于 RotateAnimation檀夹,它可以使 View 具有旋轉(zhuǎn)效果筋粗。
android:fromDegrees:旋轉(zhuǎn)開始的角度,比如 0炸渡;
android:toDegrees:旋轉(zhuǎn)結(jié)束的角度娜亿,比如180;
android:pivotX:旋轉(zhuǎn)軸點的 x偶摔;
android:pivotY:旋轉(zhuǎn)軸點的 y暇唾;
<alpha>表示透明動畫。對應(yīng)的 AlphaAnimation辰斋。
android:fromAlpha:表示透明度的起始值策州,比如0.1
android:toAlpha:表示透明度的結(jié)束值,比如1
上面都只是很簡單的介紹了XM格式宫仗,具體的使用方法還是看文檔够挂,我們還有一些常用的屬性如下
android:duration:動畫的時間
android:fillAfter:動畫結(jié)束之后是否停留在結(jié)束的位置
演示一個一秒鐘平移 100 加旋轉(zhuǎn) 360 度然后復(fù)原的案例:
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="false">
<translate
android:fromYDelta="0"
android:fromXDelta="0"
android:toXDelta="100"
android:toYDelta="100"
android:duration ="1000"
android:interpolator = "@android:anim/linear_interpolator"
/>
<rotate
android:duration ="1000"
android:fromDegrees="0"
android:toDegrees="360"
/>
</set>
再加一個代碼寫一個 透明動畫:
Animation animation = AnimationUtils.loadAnimation(MainActivity.this, R.anim.my_anim);
button.startAnimation(animation);
//代碼動畫
AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1);
alphaAnimation.setDuration(1000);
animation.setAnimationListener(new Animation.AnimationListener() {
//開始
@Override
public void onAnimationStart(Animation animation) {}
//結(jié)束
@Override
public void onAnimationEnd(Animation animation) {}
//重復(fù)
@Override
public void onAnimationRepeat(Animation animation) { }
});
button2.startAnimation(alphaAnimation);
7.1.2 自定義 View 動畫
自定義動畫只需要繼承 Animation,然后重寫它的 initialize 和 applyTransformation 方法
- initialize:初始化
-
applyTransformation:進(jìn)行相應(yīng)的矩陣變換藕夫,很多時候需要采用 Camera 來簡化矩陣變換的過程孽糖。
GIF.gif
可以參照 ApiDemos 中的 Rotate3dAnimation。
7.1.3 幀動畫
幀動畫使用很簡單毅贮,但是比較容易引起 OOM办悟,所以要避免使用大尺寸圖片。
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="@mipmap/timg" android:duration="500"/>
<item android:drawable="@mipmap/timgb" android:duration="500"/>
<item android:drawable="@mipmap/timgc" android:duration="500"/>
</animation-list>
button.setBackgroundResource(R.drawable.my_list);
AnimationDrawable background = (AnimationDrawable) button.getBackground();
background.start();
7.2 View 動畫的特殊使用場景
7.2.1 LayoutAnimation
LayoutAnimation 作用于 ViewGroup滩褥,為 ViewGroup 指定一個動畫病蛉,這樣當(dāng)它的子元素出場時都會具有這種動畫效果。
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:delay="0.5"
android:animationOrder="normal"
android:animation="@anim/anim_item">
</layoutAnimation>
android:delay
表示子元素開始動畫的延遲,0.5 就是一半的時間周期铺然。android:animationOrder
表示子元素動畫的順序俗孝。normal:順序顯示
reverse:逆向顯示
random:隨機(jī)顯示
android:animation
為子元素指定具體的入場動畫。
先新建一個 set 動畫集合魄健,里面是從透明到不透明并且平移的一個效果
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="300"
android:interpolator="@android:anim/accelerate_interpolator"
android:shareInterpolator="true" >
<alpha android:fromAlpha="0.0" android:toAlpha="1.0" />
<translate android:fromXDelta="500" android:toXDelta="0" />
</set>
新建一個 layoutAnimation 赋铝,設(shè)置顯示樣式效果
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:animation="@anim/anim_item"
android:animationOrder="normal"
android:delay="0.5">
</layoutAnimation>
在 XML 中指定 LayoutAnimation
<ListView
android:id="@+id/list_view"
android:layoutAnimation="@anim/my_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
或者可以通過 LayoutAnimationConreoller 來實現(xiàn)
Animation animation = AnimationUtils.loadAnimation(this, R.anim.anim_item);
LayoutAnimationController controller = new LayoutAnimationController(animation);
controller.setDelay(0.5f);
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
mListView.setLayoutAnimation(controller);
7.2.2 Activity 的切換效果
Activity 的自定義切換效果。主要用到 overridePendingTransition (int enterAnim沽瘦,int enterAnim)這個方法革骨。
- enterAnim: Activity 被打開時,所需要的動畫資源 id其垄;
- exitAnim: Activity 被暫停時苛蒲,所需要的動畫資源 id;
Intent intent = new Intent(MainActivity.this, ListViewActivity.class);
startActivity(intent);
overridePendingTransition(R.anim.my_anim,R.anim.my_anim);
@Override
public void finish() {
super.finish();
overridePendingTransition(R.anim.my_anim,R.anim.my_anim);
}
7.3 屬性動畫
7.3.1 使用屬性動畫
屬性動畫可以對任意對象進(jìn)行動畫而不僅僅是 View绿满,幾乎是無所不能的臂外,只要有對象這個屬性。
改變一個對象的 translationX 值喇颁。
ObjectAnimator.ofFloat(mButton, "translationX",200).start();
改變一個對象的背景顏色屬性漏健。
ObjectAnimator colorAnim = ObjectAnimator.ofInt(mButton, "backgroundColor", 0xFFFF8080, 0xFF8080FF);
colorAnim.setDuration(2000);
colorAnim.setEvaluator(new ArgbEvaluator());
//INFINITE 表示無限次
colorAnim.setRepeatCount(ValueAnimator.INFINITE);
//REVERSE 表示反轉(zhuǎn)效果
colorAnim.setRepeatMode(ValueAnimator.REVERSE);
colorAnim.start();
動畫集合,5秒內(nèi)對 View 的旋轉(zhuǎn)橘霎、平移蔫浆、縮放和透明度都進(jìn)行了改變
AnimatorSet set = new AnimatorSet();
set.playTogether(
ObjectAnimator.ofFloat(mButton,"rotationX",0,360),
ObjectAnimator.ofFloat(mButton,"rotationY",0,360),
ObjectAnimator.ofFloat(mButton,"rotation",0,-180),
ObjectAnimator.ofFloat(mButton,"translationX",0,90),
ObjectAnimator.ofFloat(mButton,"translationY",0,90),
ObjectAnimator.ofFloat(mButton,"scaleX",1,1.5f),
ObjectAnimator.ofFloat(mButton,"scaleY",0,2.5f),
ObjectAnimator.ofFloat(mButton,"alpha",1,0.25f,1)
);
set.start();
屬性動畫除了通過代碼實現(xiàn)以外,還可以通過 XML 來定義姐叁,定義在 res/animator/ 目錄下瓦盛。
<objectAnimator
android:duration="3000"
android:propertyName="x"
android:valueFrom="-50"
android:valueTo="200"
android:valueType="floatType" />
<objectAnimator
android:propertyName="y"
android:duration="3000"
android:valueFrom="1"
android:valueTo="300"
android:valueType="floatType" />
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(ValueActivity.this, R.animator.my_animator);
set.setTarget(mButton);
set.start();
android:propertyName:表示屬性動畫作用對象的屬性的名稱
android:duration:表示動畫的時長
android:valueFrom:表示屬性的起始值
android:valueTo:表示屬性的結(jié)束值
android:startOffset:表示動畫的延遲時間,當(dāng)動畫開始后外潜,需要延遲多少毫秒才會真正的播放
android:repeatCount:表示動畫的重復(fù)次數(shù)原环,默認(rèn) 0,-1 表示無線循環(huán)
android:repeatMode:表示動畫的重復(fù)模式
restart:表示連續(xù)重復(fù)
reverse:表示連逆向重復(fù)处窥,就是反轉(zhuǎn)
android:valueType:表示 propertyName 有兩個屬性有 int 和 float 兩個可選項嘱吗,分別表示屬性的類型,和浮點型滔驾,另外谒麦,如果所制定的是顏色類型,那么就不需要指定 propertyName哆致,系統(tǒng)會自動對顏色類型進(jìn)行處理
實際開發(fā)建議采用代碼來實現(xiàn)绕德,簡便動態(tài)。
7.3.2 理解插值器和估值器
TimeInterpolator:中文翻譯是時間插值器的意思摊阀,他的作用是根據(jù)時間流逝的百分比來計算出當(dāng)前屬性值改變的百分比耻蛇,系統(tǒng)預(yù)置的有:
LinearInterpolator:(線性加速器剩瓶,勻速加速器),加速和減速插值器
AccelerateDecrateInterpolator:(加速減速插值器:動畫兩頭慢中間快)
DecelerateInterpolator:(減速插值器:動畫越來越慢)
TypeEvaluator:的中文翻譯是類型估值算法城丧,也叫估值器,他的作用是根據(jù)當(dāng)前屬性變化的百分比來計算變化后的屬性值豌鹤,系統(tǒng)也預(yù)設(shè)的有:
- IntEvaluator:整型
- FloatEvaluator:浮點型
- ArgbEvaluator:Color屬性
屬性動畫中的插值器和估值器很重要亡哄,他們實現(xiàn)非勻速動畫的重要手段。也可以自定義使用布疙。
public class LinearInterpolator implements Interpolator{
@Override
public float getInterpolation(float input) {
if (mFactor == 1.0f) {
return input * input;
} else {
return (float)Math.pow(input, 2);
}
}
public class MyEvaluator extends IntEvaluator {
//fraction 百分比蚊惯、startValue 開始值、endValue 結(jié)束值
@Override
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
return super.evaluate(fraction, startValue, endValue);
}
}
7.3.3 屬性動畫的監(jiān)聽器
屬性動畫提供監(jiān)聽器用于監(jiān)聽動畫的播放灵临,主要有兩個接口:
- AnimatorListener
public static interface AnimatorListener {
//開始
void onAnimationStart(Animator animation);
//結(jié)束
void onAnimationEnd(Animator animation);
//取消
void onAnimationCancel(Animator animation);
//重復(fù)
void onAnimationRepeat(Animator animation);
}
- **AnimatorUpdateListener **
public static interface AnimatorUpdateListener {
void onAnimationUpdate(ValueAnimator animation);
}
AnimatorUpdateListener 比較特殊截型,它會監(jiān)聽整個動畫過程的,每播放一幀儒溉,就會調(diào)用一次 AnimatorUpdateListener宦焦。
7.3.4 對任意屬性做動畫
給 Button 加一個動畫,增加 Button 的寬度到 500 px顿涣。View 動畫只能通過 縮放 Scale 來讓 Button 在 x 方向上被放大波闹,而且有可能超過屏幕大小,而屬性動畫可以并且不會超越屏幕涛碑。
方法 1:直接使用(TextView 和其子類)
ObjectAnimator.ofInt(mButton, "width",50000).setDuration(2000).start();
方法 2:用一個類包裝原始對象精堕,間接為其提供 get 和 set 方法。
private void performAnimate() {
ViewWrapper viewWrapper = new ViewWrapper(mButton);
ObjectAnimator.ofInt(viewWrapper, "width",500).setDuration(2000).start();
}
public static class ViewWrapper {
private View mTarget;
public ViewWrapper(View target) {
mTarget = target;
}
public int getWidth() {
return mTarget.getLayoutParams().width;
}
public void setWidth(int width) {
mTarget.getLayoutParams().width = width;
mTarget.requestLayout();
}
}
ViewWrapper viewWrapper = new ViewWrapper(mButton);
ObjectAnimator.ofInt(viewWrapper, "width",500).setDuration(2000).start();
方法 3:采用 ValueAnimator蒲障,監(jiān)聽動畫過程的每一幀歹篓,自己實現(xiàn)屬性的改變
private void performAnimator(final View target, final int start, final int end) {
ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
//持有一個IntEvaluator對象,方便下面估值的時候使用
private IntEvaluator mEvaluator = new IntEvaluator();
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//獲得當(dāng)前動畫的進(jìn)度值揉阎,整形1-100之間
int currentValue = (int) animation.getAnimatedValue();
//獲得當(dāng)前進(jìn)度占整個動畫之間的比例庄撮,浮點0-1之間
float fraction = animation.getAnimatedFraction();
//直接使用整形估值器,通過比例計算寬度余黎,然后再設(shè)置給 Button
target.getLayoutParams().width = mEvaluator.evaluate(fraction, start, end);
target.requestLayout();
}
});
valueAnimator.setDuration(5000).start();
}
performAnimate(mButton,mButton.getWidth(),5000);
方法 4:給你的對象加上 get 和 set重窟,如果你有權(quán)限的話(一般沒有,所以可以不用)
7.3.5 屬性動畫的工作原理
屬性動畫要求動畫作用的對象提供該屬性的 set 方法惧财,屬性動畫根據(jù)那你傳遞的該屬性的初始值和最終值巡扇,以動畫的效果多次去調(diào)用 set 方法,每次傳遞給 set 方法的值都不一樣垮衷,確切的來說隨著時間的推移厅翔,所傳遞的值越來越接近最終值,如果動畫的時候沒有傳遞初始值搀突,那么還要提供 get 方法刀闷,因為系統(tǒng)需要獲取屬性的初始值。這就上面的 方法 2 需要設(shè)置 get 和 set 的原因。
一句話:最后是通過反射來調(diào)用甸昏。(源碼不清不楚顽分,先放著)
7.4 使用動畫的注意事項
OOM 問題
這個問題主要出現(xiàn)在幀動畫,當(dāng)圖片較多且大就容易出現(xiàn)施蜜,這個時候盡量避免使用幀動畫卒蘸。內(nèi)存泄漏
在屬性動畫中有設(shè)置無線循環(huán)的動畫,這類動畫要在退出時要及時停止翻默,View 動畫并不在此問題缸沃。** 兼容性問題**
動畫在 3.0 以下的系統(tǒng)上有兼容問題,要做好適配工作修械。View 動畫的問題
View 動畫是對 View 的影像做動畫趾牧,并不是正真的改變 View 的狀態(tài),調(diào)用方法不能正常使用時肯污,調(diào)用 View.clearAnimation 清除可以解決翘单。不要使用 px
在進(jìn)行動畫的過程中,要使用 dp仇箱,用 px 會有適配問題县恕。動畫元素的交互
3.0 之前的問題忽略,3.0 以后屬性動畫的點擊事件觸發(fā)位置為移動后的位置剂桥,但是 View 動畫任然在原位置忠烛。硬件加速
使用動畫的過程中,建議開啟硬件加速权逗,這樣會提供動畫的流暢性美尸。