動畫類型
- View Animation(Tween Animation 補間動畫)
只能支持簡單的縮放、平移、旋轉、透明度等基本的動畫,且有一定的局限性
動畫時View的真正的View的屬性保持不變,實際位置未改變
原理:提供動畫的起始和結束狀態信息,中間的狀態根據上述類里差值器算法填充 - Drawable Animation(Frame Animation 幀動畫)
- Property Animation(屬性動畫)
它更改的是對象的實際屬性,
Property Animation屬性
- Duration:動畫的持續時間
- TimeInterpolation:屬性值的計算方式,如先快后慢
- TypeEvaluator:根據屬性的開始、結束值與TimeInterpolation計算出的因子計算出當前時間的屬性值
- Repeat Count and behavoir:重復次數與方式,如播放3次、5次、無限循環,可以此動畫一直重復,或播放完時再反向播放
- Animation sets:動畫集合,即可以同時對一個對象應用幾個動畫,這些動畫可以同時播放也可以對不同動畫設置不同開始偏移
- Frame refreash delay:多少時間刷新一次,即每隔多少時間計算一次屬性值,默認為10ms,最終刷新時間還受系統進程調度與硬件的影響
Property Animation 動畫流程
ValueAnimator
ValueAnimator包含Property Animation動畫的所有核心功能,如動畫時間,開始、結束屬性值,相應時間屬性值計算方法等。應用Property Animation有兩個步聚:
- 計算屬性值
- 根據屬性值執行相應的動作,如改變對象的某一屬性。(需要在onAnimationUpdate中傳入執行動畫的對象)
/**
* 自由落體
* @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)
{
// //這個函數中會傳入ValueAnimator對象做為參數,通過這個ValueAnimator對象的getAnimatedValue()函數可以得到當前的屬性值
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,要指定一個對象及該對象的一個屬性,例如
- 常用方法有ofFloat(),ofInt(),ofObject(),ofArgb(),ofPropertyValuesHolder()。
- 屬性動畫可用的屬性
答案是:任何一切帶有set開頭的方法屬性名字。可能我們常用的有: - 平移 translationX,translationY, X,Y。
- 縮放 scaleX,scaleY。
- 旋轉 rotationX, rotationY。
- 透明度 alpha。
也就是說我們所有控件都有以上setTranslationX(),setScaleX(),setRotationX(),setAlpha()等方法。
我們不僅限于這幾個屬性,就拿TextView控件來說,只要是TextView有的屬性都可以用來實現動畫效果,比如 字體大小:“textColor”,字體顏色“textSize”等。
限制:對象應該有一個setter函數:set<PropertyName>(駝峰命名法)及要有相應屬性的getter方法:get<PropertyName>
且應返回值類型應與相應的setter方法的參數類型一致。
如果上述條件不滿足,則不能用ObjectAnimator,應用ValueAnimator代替。
ObjectAnimator animator = ObjectAnimator.ofFloat(imageView, 'alpha', 1.0f, 0.3f, 1.0F);
animator.setDuration(2000);//動畫時間
animator.setInterpolator(new BounceInterpolator());//動畫插值
animator.setRepeatCount(-1);//設置動畫重復次數
animator.setRepeatMode(ValueAnimator.RESTART);//動畫重復模式
animator.setStartDelay(1000);//動畫延時執行
animator.start();//啟動動畫
```
> 根據應用動畫的對象或屬性的不同,如果內部沒有調用view的重繪,可能需要在onAnimationUpdate函數中調用invalidate()函數刷新視圖。
###組合動畫
- **組合動畫1–AnimatorSet的使用**
這個類提供了一個play()方法,如果我們向這個方法中傳入一個Animator對象(ValueAnimator或ObjectAnimator)將會返回一個AnimatorSet.Builder的實例,AnimatorSet.Builder中包括以下四個方法:
- after(Animator anim) 將現有動畫插入到傳入的動畫之后執行
- after(long delay) 將現有動畫延遲指定毫秒后執行
- before(Animator anim) 將現有動畫插入到傳入的動畫之前執行
- with(Animator anim) 將現有動畫和傳入的動畫同時執行
> Android 除了提供play(),還有playSequentially(),playTogether() 可供使用,可傳入一個或者多個動畫對象(,隔開),或者動畫集合
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);
//組合動畫方式1
AnimatorSet set = new AnimatorSet();
((set.play(animator).with(animator1).before(animator2)).before(animator3)).after(animator4);
set.setDuration(5000);
set.start();
```
-
組合動畫2–PropertyValuesHolder的使用
使用方法ObjectAnimator.ofPropertyValuesHolder(Object target,PropertyValuesHolder… values);第一個參數是動畫的目標對象,之后的參數是PropertyValuesHolder類的實例,可以有多個這樣的實例。代碼如下:
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);
```
- **組合動畫3-ViewPropertyAnimator(多屬性動畫)**
// 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
### 動畫監聽
- animator.addListener(new Animator.AnimatorListener(){});//監聽動畫開始,結束,取消,重復(四種都包括)
- animator.addListener(new AnimatorListenerAdapter(){});
推薦,可代替AnimatorListener,需要監聽動畫開始,結束,取消,重復那種就直接實現那種方法就行
其實AnimatorListenerAdapter的源碼只是一個實現了AnimatorListener接口的抽象類而已
- animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){});
更加精確的方法來時刻監聽當前動畫的執行情況,可以讀取到動畫的每個更新值了
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float value = (float) animation.getAnimatedValue();
//可以根據自己的需要來獲取動畫更新值。
Log.e('TAG', 'the animation value is ' + value);
}
});
###Keyframes
keyFrame是一個 時間/值 對,通過它可以定義一個在特定時間的特定狀態,即關鍵幀,而且在兩個keyFrame之間可以定義不同的Interpolator,就好像多個動畫的拼接,第一個動畫的結束點是第二個動畫的開始點。KeyFrame是抽象類,要通過ofInt(),ofFloat(),ofObject()獲得適當的KeyFrame,然后通過PropertyValuesHolder.ofKeyframe獲得PropertyValuesHolder對象,如以下例子:
/*
- 動畫效果:btn對象的width屬性值使其:
- 開始時 Width=400
- 動畫開始1/4時 Width=200
- 動畫開始1/2時 Width=400
- 動畫開始3/4時 Width=100
- 動畫結束時 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' /><!--動畫值的類型-->
</set>
- 通過AnimatorInflater.loadAnimator方法加載xml動畫返回一個Animator的對象,然后調用setTarget方法給動畫設置對象調用哪個start啟動動畫即可完成xml動畫效果
Animator animator = AnimatorInflater.loadAnimator(context, R.animator.anim_file);
animator.setTarget(view);
animator.start();
###LayoutAnimation 布局動畫
- LayoutTransition為布局的容器設置動畫,當容器中的視圖層次發生變化時存在過渡的動畫效果。
- 過渡類型:
- LayoutTransition.APPEARING 當一個View在ViewGroup中出現時,對**此View**設置的動畫
- LayoutTransition.CHANGE_APPEARING 當一個View在ViewGroup中出現時,對此View對其他View位置造成影響,對**其他View**設置的動畫
- LayoutTransition.DISAPPEARING 當一個View在ViewGroup中消失時,對**此View**設置的動畫
- LayoutTransition.CHANGE_DISAPPEARING 當一個View在ViewGroup中消失時,對此View對其他View位置造成影響,對其**他View**設置的動畫
- LayoutTransition.CHANGE 不是由于View出現或消失造成對其他View位置造成影響,然后對**其他View**設置的動畫。
- 步驟:
1. 實例化一個LayoutTransition對象
3. 使用setAnimator 設置LayoutTransition對象的動畫,這個動畫包含了上述四個類型。可以使用android自帶的動畫,也可以使用自定義動畫。本例中的自定義動畫效果和上例一樣。
2. setLayoutTransition指定container的LayoutTransition對象
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));//可用使用自定義動畫
transition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING,
null);
mGridLayout.setLayoutTransition(transition);