視圖動畫(補間)
以下爲Android常用的視圖動畫類,xml動畫這裏不做詳解。
基本動畫
-
ScaleAnimation(縮放動畫)可變化控件的大小
/** * Scale動畫裏x、Y指這個控件的寬高百分比,取值0~1 * * @param fromX 動畫開始的X。 * @param toX 動畫結束的X。 * @param fromY 動畫開始的y。 * @param toY 動畫結束的y。 * * @param 動畫開始時X座標類型,可以理解爲從控件的哪個位置開始,下方動畫同值。 * 取值範圍爲ABSOLUTE(絕對位置)、RELATIVE_TO_SELF(以自身寬或高爲參考)、 * RELATIVE_TO_PARENT(以父控件寬或高爲參考)。 * @param pivotXValue 取值0~1(1 is 100%) * @param pivotYType 動畫開始時座標類型 * 取值範圍爲ABSOLUTE(絕對位置)、RELATIVE_TO_SELF(以自身寬或高爲參*考)、 * RELATIVE_TO_PARENT(以父控件寬或高爲參考)。 * @param pivotYValue 取值0~1(1 is 100%) * 下面代碼動畫表示:從控件的左上角位置開始,放大1.5倍 */ val animation2 = ScaleAnimation(1f, 1.5f, 1f, 1.5f, ScaleAnimation.RELATIVE_TO_SELF, 0f, ScaleAnimation.RELATIVE_TO_SELF, 0f) animation2.duration = 700
-
RotateAnimation
/** * 旋轉動畫 * @param fromDegrees 開始前角度 0代表當前無角度 * @param toDegrees 動畫結束角度 * @param pivotXType * @param pivotXValue * @param pivotYType * @param pivotYValue * 下面代碼動畫表示:從控件的中心旋轉360° */ val animation3 = RotateAnimation(0f, 360f, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f)
-
TranslateAnimation
/** * 平移動畫 * @param fromXDelta 動畫前X座標 * @param toXDelta 動畫結束X座標 * @param fromYDelta 動畫前Y * @param toYDelta 動畫結束Y座標 * 下面代碼動畫表示:從當前控件的起始位置0,向上Y移動100像素 */ var animation1 = TranslateAnimation(0f, 0f, 0f, -100f)
-
AlphaAnimation
/** * 透明度動畫 * @param fromAlpha 動畫前View的通明度 * @param toAlpha 動畫結束時View的通明度 */ val animation4 = AlphaAnimation(1f, 0.1f)
進階用法
AnimationSet組合動畫,對View運行組合動畫,這裏需要注意AnimationSet中添加的動畫是一起執行的,不能設定動畫的先後執行順序,同樣也不能在動畫的過程中進行操作。
/**
* AnimationSet 有兩個構造函數
* AnimationSet(Context context, AttributeSet attrs) // 傳入一組動畫屬性attr(執行時間等)
* AnimationSet(boolean shareInterpolator) // 是否共用插值器
* 注意事項:
* 1.AnimationSet設定duration值(執行時長),會使集合中animation duration屬性值失效
* 2.AnimationSet設定repeatCount值(重複次數)無效,只會取子動畫設定值
* 3.AnimationSet設定repeatMode值(REVERSE從結束位置執行反動畫,RESTART重新執行動畫),會使子動畫repeatMode無效
*/
/** AnimationSet源碼
*/
class AnimationSet extends Animation {
@Override
public long getDuration() {
final ArrayList<Animation> animations = mAnimations;
final int count = animations.size();
long duration = 0;
boolean durationSet = (mFlags & PROPERTY_DURATION_MASK) == PROPERTY_DURATION_MASK;
if (durationSet) { //如果AnimationSet有設置duration,則取AnimationSet的duration
duration = mDuration;
} else { // 取子動畫中最大的duration
for (int i = 0; i < count; i++) {
duration = Math.max(duration, animations.get(i).getDuration());
}
}
return duration;
}
}
//使用方式
val animationTest = AnimationSet(true)
animationTest.addAnimation(animation1)
animationTest.addAnimation(animation2)
animationTest.addAnimation(animation3)
animationTest.addAnimation(animation4)
animationTest.duration = 900
animationTest.interpolator = LinearInterpolator() //線性插值器
視圖動畫原理解析
/**
* view.startAnimation(animation) view與animation產生聯繫
* 初始化動畫的啓動設定爲第一禎,調用reset方法,也就是說不管動畫是否在執行過程,再次執行動畫依然回到第一 * 幀。接着invalidate開始重繪,UI重繪機制這裏不做詳解,我們直接找到getAnimation()調用的地方 * view.draw(Canvas canvas, ViewGroup parent, long drawingTime)
*/
public void startAnimation(Animation animation) {
animation.setStartTime(Animation.START_ON_FIRST_FRAME);
setAnimation(animation);
invalidateParentCaches();
invalidate(true);
}
public void setAnimation(Animation animation) {
mCurrentAnimation = animation;
if (animation != null) {
if (mAttachInfo != null && mAttachInfo.mDisplayState == Display.STATE_OFF
&& animation.getStartTime() == Animation.START_ON_FIRST_FRAME) {
animation.setStartTime(AnimationUtils.currentAnimationTimeMillis());
}
animation.reset();
}
}
/**View類*/
@UiThread
public class View implements Drawable.Callback, KeyEvent.Callback,
AccessibilityEventSource {
boolean draw(Canvas canvas, ViewGroup parent, long drawingTime) {
final boolean hardwareAcceleratedCanvas = canvas.isHardwareAccelerated();
// ...省略代碼
final Animation a = getAnimation();
if (a != null) {
//處理視圖活動Animation
more = applyLegacyAnimation(parent, drawingTime, a, scalingRequired);
}
}
private boolean applyLegacyAnimation(ViewGroup parent, long drawingTime,
Animation a, boolean scalingRequired) {
//..
final Transformation t = parent.getChildTransformation();
boolean more = a.getTransformation(drawingTime, t, 1f);
if (more) {
// 判斷動畫是否過期,如果沒有過期,則去執行parent的invalidate,會重新執行child重繪
// 繪製下一幀動畫,16ms一幀
parent.invalidate(left, top, left + (int) (region.width() + .5f),
top + (int) (region.height() + .5f));
}
}
}
/**Animatio類*/
public abstract class Animation implements Cloneable {
public boolean getTransformation(long currentTime, Transformation outTransformation) {
if (mStartTime == -1) {
mStartTime = currentTime;
}
final long startOffset = getStartOffset();
final long duration = mDuration;
float normalizedTime;
if (duration != 0) {
// 先初始化動畫的啓動進度,比如1個4s的動畫,計算現在動畫進度百分比
normalizedTime = ((float) (currentTime - (mStartTime + startOffset))) /
(float) duration;
} else {
normalizedTime = currentTime < mStartTime ? 0.0f : 1.0f;
}
//判斷動畫是否過期
final boolean expired = normalizedTime >= 1.0f || isCanceled();
mMore = !expired;
if (!mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f);
if ((normalizedTime >= 0.0f || mFillBefore) && (normalizedTime <= 1.0f || mFillAfter)) {
if (!mStarted) {
fireAnimationStart();
mStarted = true;
if (NoImagePreloadHolder.USE_CLOSEGUARD) {
guard.open("cancel or detach or getTransformation");
}
}
if (mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f);
if (mCycleFlip) {
normalizedTime = 1.0f - normalizedTime;
}
final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime); // 通過插值器計算出平穩值
//執行動畫,調用子類ScaleAnimation、RotateAnimation的實現方法,這裏說明我們也可以自定義Animation,通過重寫applyTransformation方法,執行自己的動畫邏輯
applyTransformation(interpolatedTime, outTransformation);
}
if (expired) {
if (mRepeatCount == mRepeated || isCanceled()) {
if (!mEnded) {
// ... 動畫結束
fireAnimationEnd();
}
} else {
if (mRepeatCount > 0) {
mRepeated++;
}
if (mRepeatMode == REVERSE) {
mCycleFlip = !mCycleFlip;
}
mStartTime = -1;
mMore = true;
// 判斷動畫RepeatCount,是否重複執行
fireAnimationRepeat();
}
}
return mMore;
}
}
視圖動畫的侷限性
- 只能作用於view,但有時需求不是對於整個view的,而只是對view的某個屬性的,例如顏色的變化,也無法對非View的對象進行動畫處理。
- 只改變了view的視覺效果而已,修改了視圖繪製的地方,例如控件的點擊,還是動畫前控件的位置。
- 動畫效果固定,動畫類型只有四種,縮放,平移,旋轉,透明度的基本動畫,無法對其他屬性進行操作。
- 動畫雖然可以添加監聽,但是動畫開始後無法對動畫的執行過程進行控制。
視圖動畫的優點
- 使用方便,能滿足基礎動畫效果