動(dòng)畫(huà)類型
- View Animation(Tween Animation 補(bǔ)間動(dòng)畫(huà))
只能支持簡(jiǎn)單的縮放样傍、平移捂贿、旋轉(zhuǎn)渤弛、透明度等基本的動(dòng)畫(huà)泛释,且有一定的局限性
動(dòng)畫(huà)時(shí)View的真正的View的屬性保持不變滤愕,實(shí)際位置未改變
原理:提供動(dòng)畫(huà)的起始和結(jié)束狀態(tài)信息,中間的狀態(tài)根據(jù)上述類里差值器算法填充 - Drawable Animation(Frame Animation 幀動(dòng)畫(huà))
- Property Animation(屬性動(dòng)畫(huà))
它更改的是對(duì)象的實(shí)際屬性怜校,
Property Animation屬性
- Duration:動(dòng)畫(huà)的持續(xù)時(shí)間
- TimeInterpolation:屬性值的計(jì)算方式间影,如先快后慢
- TypeEvaluator:根據(jù)屬性的開(kāi)始、結(jié)束值與TimeInterpolation計(jì)算出的因子計(jì)算出當(dāng)前時(shí)間的屬性值
- Repeat Count and behavoir:重復(fù)次數(shù)與方式茄茁,如播放3次魂贬、5次、無(wú)限循環(huán)胰丁,可以此動(dòng)畫(huà)一直重復(fù)随橘,或播放完時(shí)再反向播放
- Animation sets:動(dòng)畫(huà)集合,即可以同時(shí)對(duì)一個(gè)對(duì)象應(yīng)用幾個(gè)動(dòng)畫(huà)锦庸,這些動(dòng)畫(huà)可以同時(shí)播放也可以對(duì)不同動(dòng)畫(huà)設(shè)置不同開(kāi)始偏移
- Frame refreash delay:多少時(shí)間刷新一次机蔗,即每隔多少時(shí)間計(jì)算一次屬性值,默認(rèn)為10ms甘萧,最終刷新時(shí)間還受系統(tǒng)進(jìn)程調(diào)度與硬件的影響
Property Animation 動(dòng)畫(huà)流程
ValueAnimator
ValueAnimator包含Property Animation動(dòng)畫(huà)的所有核心功能萝嘁,如動(dòng)畫(huà)時(shí)間,開(kāi)始扬卷、結(jié)束屬性值牙言,相應(yīng)時(shí)間屬性值計(jì)算方法等。應(yīng)用Property Animation有兩個(gè)步聚:
- 計(jì)算屬性值
- 根據(jù)屬性值執(zhí)行相應(yīng)的動(dòng)作怪得,如改變對(duì)象的某一屬性咱枉。(需要在onAnimationUpdate中傳入執(zhí)行動(dòng)畫(huà)的對(duì)象)
/**
* 自由落體
* @param view
*/
ValueAnimator animator = ValueAnimator.ofFloat(0, mScreenHeight
- mBlueBall.getHeight());
animator.setTarget(mBlueBall);
animator.setDuration(1000).start();
// animator.setInterpolator(new CycleInterpolator(3));
animator.addUpdateListener(new AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
// //這個(gè)函數(shù)中會(huì)傳入ValueAnimator對(duì)象做為參數(shù),通過(guò)這個(gè)ValueAnimator對(duì)象的getAnimatedValue()函數(shù)可以得到當(dāng)前的屬性值
mBlueBall.setTranslationY((Float) animation.getAnimatedValue());
}
});
}
/**
* 拋物線
* @param view
*/
public void paowuxian(View view)
{
ValueAnimator valueAnimator = new ValueAnimator();
valueAnimator.setDuration(3000);
valueAnimator.setObjectValues(new PointF(0, 0));
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.setEvaluator(new TypeEvaluator<PointF>()
{
// fraction = t / duration
@Override
public PointF evaluate(float fraction, PointF startValue,
PointF endValue)
{
Log.e(TAG, fraction * 3 + "");
// x方向200px/s 徒恋,則y方向0.5 * 10 * t
PointF point = new PointF();
point.x = 200 * fraction * 3;
point.y = 0.5f * 200 * (fraction * 3) * (fraction * 3);
return point;
}
});
valueAnimator.start();
valueAnimator.addUpdateListener(new AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
PointF point = (PointF) animation.getAnimatedValue();
mBlueBall.setX(point.x);
mBlueBall.setY(point.y);
}
});
}
ObjectAnimator
ObjectAnimator繼承自ValueAnimator蚕断,要指定一個(gè)對(duì)象及該對(duì)象的一個(gè)屬性,例如
- 常用方法有ofFloat(),ofInt()入挣,ofObject()亿乳,ofArgb(),ofPropertyValuesHolder()径筏。
- 屬性動(dòng)畫(huà)可用的屬性
答案是:任何一切帶有set開(kāi)頭的方法屬性名字葛假。可能我們常用的有: - 平移 translationX滋恬,translationY, X聊训,Y。
- 縮放 scaleX夷恍,scaleY魔眨。
- 旋轉(zhuǎn) rotationX媳维, rotationY。
- 透明度 alpha遏暴。
也就是說(shuō)我們所有控件都有以上setTranslationX(),setScaleX(),setRotationX(),setAlpha()等方法侄刽。
我們不僅限于這幾個(gè)屬性,就拿TextView控件來(lái)說(shuō)朋凉,只要是TextView有的屬性都可以用來(lái)實(shí)現(xiàn)動(dòng)畫(huà)效果州丹,比如 字體大小:“textColor”杂彭,字體顏色“textSize”等墓毒。
限制:對(duì)象應(yīng)該有一個(gè)setter函數(shù):set<PropertyName>(駝峰命名法)及要有相應(yīng)屬性的getter方法:get<PropertyName>
且應(yīng)返回值類型應(yīng)與相應(yīng)的setter方法的參數(shù)類型一致。
如果上述條件不滿足亲怠,則不能用ObjectAnimator所计,應(yīng)用ValueAnimator代替。
ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, 'alpha', 1.0f, 0.3f, 1.0F);
animator.setDuration(2000);//動(dòng)畫(huà)時(shí)間
animator.setInterpolator(new BounceInterpolator());//動(dòng)畫(huà)插值
animator.setRepeatCount(-1);//設(shè)置動(dòng)畫(huà)重復(fù)次數(shù)
animator.setRepeatMode(ValueAnimator.RESTART);//動(dòng)畫(huà)重復(fù)模式
animator.setStartDelay(1000);//動(dòng)畫(huà)延時(shí)執(zhí)行
animator.start();//啟動(dòng)動(dòng)畫(huà)
```
> 根據(jù)應(yīng)用動(dòng)畫(huà)的對(duì)象或?qū)傩缘牟煌呕啵绻麅?nèi)部沒(méi)有調(diào)用view的重繪主胧,可能需要在onAnimationUpdate函數(shù)中調(diào)用invalidate()函數(shù)刷新視圖。
###組合動(dòng)畫(huà)
- **組合動(dòng)畫(huà)1–AnimatorSet的使用**
這個(gè)類提供了一個(gè)play()方法习勤,如果我們向這個(gè)方法中傳入一個(gè)Animator對(duì)象(ValueAnimator或ObjectAnimator)將會(huì)返回一個(gè)AnimatorSet.Builder的實(shí)例踪栋,AnimatorSet.Builder中包括以下四個(gè)方法:
- after(Animator anim) 將現(xiàn)有動(dòng)畫(huà)插入到傳入的動(dòng)畫(huà)之后執(zhí)行
- after(long delay) 將現(xiàn)有動(dòng)畫(huà)延遲指定毫秒后執(zhí)行
- before(Animator anim) 將現(xiàn)有動(dòng)畫(huà)插入到傳入的動(dòng)畫(huà)之前執(zhí)行
- with(Animator anim) 將現(xiàn)有動(dòng)畫(huà)和傳入的動(dòng)畫(huà)同時(shí)執(zhí)行
> Android 除了提供play(),還有playSequentially(),playTogether() 可供使用,可傳入一個(gè)或者多個(gè)動(dòng)畫(huà)對(duì)象(图毕,隔開(kāi))夷都,或者動(dòng)畫(huà)集合
ObjectAnimator animator = ObjectAnimator.ofInt(container, "backgroundColor", 0xFFFF0000, 0xFFFF00FF);
ObjectAnimator animator1 = ObjectAnimator.ofFloat(view, "translationX", 0.0f, 200.0f, 0f);
ObjectAnimator animator2 = ObjectAnimator.ofFloat(view, "scaleX", 1.0f, 2.0f);
ObjectAnimator animator3 = ObjectAnimator.ofFloat(view, "rotationX", 0.0f, 90.0f, 0.0F);
ObjectAnimator animator4 = ObjectAnimator.ofFloat(view, "alpha", 1.0f, 0.2f, 1.0F);
//組合動(dòng)畫(huà)方式1
AnimatorSet set = new AnimatorSet();
((set.play(animator).with(animator1).before(animator2)).before(animator3)).after(animator4);
set.setDuration(5000);
set.start();
```
-
組合動(dòng)畫(huà)2–PropertyValuesHolder的使用
使用方法ObjectAnimator.ofPropertyValuesHolder(Object target,PropertyValuesHolder… values);第一個(gè)參數(shù)是動(dòng)畫(huà)的目標(biāo)對(duì)象予颤,之后的參數(shù)是PropertyValuesHolder類的實(shí)例囤官,可以有多個(gè)這樣的實(shí)例。代碼如下:
PropertyValuesHolder valuesHolder = PropertyValuesHolder.ofFloat("translationX", 0.0f, 300.0f);
PropertyValuesHolder valuesHolder1 = PropertyValuesHolder.ofFloat("scaleX", 1.0f, 1.5f);
PropertyValuesHolder valuesHolder2 = PropertyValuesHolder.ofFloat("rotationX", 0.0f, 90.0f, 0.0F);
PropertyValuesHolder valuesHolder3 = PropertyValuesHolder.ofFloat("alpha", 1.0f, 0.3f, 1.0F);
ObjectAnimator objectAnimator = ObjectAnimator.ofPropertyValuesHolder(view, valuesHolder, valuesHolder1, valuesHolder2, valuesHolder3);
objectAnimator.setDuration(2000).start();
//類似于AnimatorSet.playTogether(Animator... items);
```
- **組合動(dòng)畫(huà)3-ViewPropertyAnimator(多屬性動(dòng)畫(huà))**
// need API12
ViewPropertyAnimator animator=mBlueBall.animate()
.alpha(0)
.y(mScreenHeight / 2).setDuration(1000)
// need API 12
.withStartAction(new Runnable()
{
@Override
public void run()
{
Log.e(TAG, "START");
}
// need API 16
}).withEndAction(new Runnable()
{
@Override
public void run()
{
Log.e(TAG, "END");
runOnUiThread(new Runnable()
{
@Override
public void run()
{
mBlueBall.setY(0);
mBlueBall.setAlpha(1.0f);
}
});
}
}).start();
}
> 注意:使用ViewPropertyAnimator類需要API>=12
### 動(dòng)畫(huà)監(jiān)聽(tīng)
- animator.addListener(new Animator.AnimatorListener(){});//監(jiān)聽(tīng)動(dòng)畫(huà)開(kāi)始蛤虐,結(jié)束治拿,取消,重復(fù)(四種都包括)
- animator.addListener(new AnimatorListenerAdapter(){});
推薦笆焰,可代替AnimatorListener,需要監(jiān)聽(tīng)動(dòng)畫(huà)開(kāi)始见坑,結(jié)束嚷掠,取消,重復(fù)那種就直接實(shí)現(xiàn)那種方法就行
其實(shí)AnimatorListenerAdapter的源碼只是一個(gè)實(shí)現(xiàn)了AnimatorListener接口的抽象類而已
- animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){});
更加精確的方法來(lái)時(shí)刻監(jiān)聽(tīng)當(dāng)前動(dòng)畫(huà)的執(zhí)行情況荞驴,可以讀取到動(dòng)畫(huà)的每個(gè)更新值了
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
//可以根據(jù)自己的需要來(lái)獲取動(dòng)畫(huà)更新值不皆。
Log.e('TAG', 'the animation value is ' + value);
}
});
###Keyframes
keyFrame是一個(gè) 時(shí)間/值 對(duì),通過(guò)它可以定義一個(gè)在特定時(shí)間的特定狀態(tài)熊楼,即關(guān)鍵幀霹娄,而且在兩個(gè)keyFrame之間可以定義不同的Interpolator,就好像多個(gè)動(dòng)畫(huà)的拼接,第一個(gè)動(dòng)畫(huà)的結(jié)束點(diǎn)是第二個(gè)動(dòng)畫(huà)的開(kāi)始點(diǎn)犬耻。KeyFrame是抽象類踩晶,要通過(guò)ofInt(),ofFloat(),ofObject()獲得適當(dāng)?shù)腒eyFrame,然后通過(guò)PropertyValuesHolder.ofKeyframe獲得PropertyValuesHolder對(duì)象枕磁,如以下例子:
/*
- 動(dòng)畫(huà)效果:btn對(duì)象的width屬性值使其:
- 開(kāi)始時(shí) Width=400
- 動(dòng)畫(huà)開(kāi)始1/4時(shí) Width=200
- 動(dòng)畫(huà)開(kāi)始1/2時(shí) Width=400
- 動(dòng)畫(huà)開(kāi)始3/4時(shí) Width=100
- 動(dòng)畫(huà)結(jié)束時(shí) Width=500
*/
Keyframe kf0 = Keyframe.ofInt(0, 400);
Keyframe kf1 = Keyframe.ofInt(0.25f, 200);
Keyframe kf2 = Keyframe.ofInt(0.5f, 400);
Keyframe kf4 = Keyframe.ofInt(0.75f, 100);
Keyframe kf3 = Keyframe.ofInt(1f, 500);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("width", kf0, kf1, kf2, kf4, kf3);
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(btn2, pvhRotation);
rotationAnim.setDuration(2000);
### Property Animation在XML中使用
- xml文件放在res/animator/中
<set xmlns:android='http://schemas.android.com/apk/res/android'
android:duration='2000'
android:ordering='sequentially'>
<objectAnimator
android:propertyName='translationX'
android:valueFrom='0'
android:valueTo='200'
android:valueType='floatType' />
<set android:ordering='together'>
<objectAnimator
android:propertyName='scaleX'
android:valueFrom='1'
android:valueTo='2'
android:valueType='floatType' />
<objectAnimator
android:propertyName='rotationX'
android:valueFrom='0'
android:valueTo='90'
android:valueType='floatType' /><!--動(dòng)畫(huà)值的類型-->
</set>
- 通過(guò)AnimatorInflater.loadAnimator方法加載xml動(dòng)畫(huà)返回一個(gè)Animator的對(duì)象渡蜻,然后調(diào)用setTarget方法給動(dòng)畫(huà)設(shè)置對(duì)象調(diào)用哪個(gè)start啟動(dòng)動(dòng)畫(huà)即可完成xml動(dòng)畫(huà)效果
Animator animator = AnimatorInflater.loadAnimator(context, R.animator.anim_file);
animator.setTarget(view);
animator.start();
###LayoutAnimation 布局動(dòng)畫(huà)
- LayoutTransition為布局的容器設(shè)置動(dòng)畫(huà),當(dāng)容器中的視圖層次發(fā)生變化時(shí)存在過(guò)渡的動(dòng)畫(huà)效果计济。
- 過(guò)渡類型:
- LayoutTransition.APPEARING 當(dāng)一個(gè)View在ViewGroup中出現(xiàn)時(shí)茸苇,對(duì)**此View**設(shè)置的動(dòng)畫(huà)
- LayoutTransition.CHANGE_APPEARING 當(dāng)一個(gè)View在ViewGroup中出現(xiàn)時(shí),對(duì)此View對(duì)其他View位置造成影響沦寂,對(duì)**其他View**設(shè)置的動(dòng)畫(huà)
- LayoutTransition.DISAPPEARING 當(dāng)一個(gè)View在ViewGroup中消失時(shí)学密,對(duì)**此View**設(shè)置的動(dòng)畫(huà)
- LayoutTransition.CHANGE_DISAPPEARING 當(dāng)一個(gè)View在ViewGroup中消失時(shí),對(duì)此View對(duì)其他View位置造成影響传藏,對(duì)其**他View**設(shè)置的動(dòng)畫(huà)
- LayoutTransition.CHANGE 不是由于View出現(xiàn)或消失造成對(duì)其他View位置造成影響腻暮,然后對(duì)**其他View**設(shè)置的動(dòng)畫(huà)。
- 步驟:
1. 實(shí)例化一個(gè)LayoutTransition對(duì)象
3. 使用setAnimator 設(shè)置LayoutTransition對(duì)象的動(dòng)畫(huà)漩氨,這個(gè)動(dòng)畫(huà)包含了上述四個(gè)類型西壮。可以使用android自帶的動(dòng)畫(huà)叫惊,也可以使用自定義動(dòng)畫(huà)款青。本例中的自定義動(dòng)畫(huà)效果和上例一樣。
2. setLayoutTransition指定container的LayoutTransition對(duì)象
LayoutTransition transition = new LayoutTransition();
transition.setAnimator(LayoutTransition.CHANGE_APPEARING,
transition.getAnimator(LayoutTransition.CHANGE_APPEARING));
transition.setAnimator(LayoutTransition.APPEARING,
null);
transition.setAnimator(LayoutTransition.APPEARING, (mAppear
.isChecked() ? ObjectAnimator.ofFloat(this, "scaleX", 1, 0): null));//可用使用自定義動(dòng)畫(huà)
transition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING,
null);
mGridLayout.setLayoutTransition(transition);