
本文的合集已經(jīng)編著成書,高級Android開發(fā)強化實戰(zhàn),歡迎各位讀友的建議和指導。在京東即可購買:https://item.jd.com/12385680.html

在應用中, 動畫效果提升用戶體驗, 主要分為View動畫和屬性動畫. View動畫變換場景圖片效果, 效果包括平移(translate), 縮放(scale), 旋轉(rotate), 透明(alpha); 屬性動畫動態(tài)地改變改變屬性, 達到動畫效果. 本文包含源碼.
本文源碼的GitHub下載地址
View動畫
動畫包含四種平移, 縮放, 旋轉, 透明, 也支持組合使用.
mAnimations = new ArrayList<>();
mAnimations.add(AnimationUtils.loadAnimation(context, R.anim.anim_translate));
mAnimations.add(AnimationUtils.loadAnimation(context, R.anim.anim_scale));
mAnimations.add(AnimationUtils.loadAnimation(context, R.anim.anim_rotate));
mAnimations.add(AnimationUtils.loadAnimation(context, R.anim.anim_alpha));
mAnimations.add(AnimationUtils.loadAnimation(context, R.anim.anim_all));
平移動畫: duration持續(xù)時間; fromXDelta起始X坐標, fromYDelta起始Y坐標; toXDelta終止X坐標, toYDelta終止Y坐標.
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true"
android:interpolator="@android:anim/accelerate_interpolator">
<!--平移動畫-->
<translate
android:duration="2000"
android:fromXDelta="50"
android:fromYDelta="-100"
android:toXDelta="0"
android:toYDelta="0"/>
</set>
fillAfter動畫完成后停留, 即在平移后不復原;interpolator變換插值器.
縮放動畫: fromXScale起始寬度比例, fromYScale起始高度比例; toXScale終止寬度比例, toYScale終止高度比例.
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!--縮放動畫-->
<scale
android:duration="2000"
android:fromXScale="0.0"
android:fromYScale="0.0"
android:toXScale="1.0"
android:toYScale="1.0"/>
</set>
旋轉動畫: fromDegrees起始角度, toDegrees終止角度; pivotX旋轉中心X坐標, pivotY旋轉中心Y坐標.
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true">
<!--旋轉動畫-->
<rotate
android:duration="2000"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="-720"/>
</set>
透明動畫: fromAlpha起始透明度, toAlpha終止透明度.
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!--透明動畫-->
<alpha
android:duration="2000"
android:fromAlpha="0.1"
android:toAlpha="1.0"/>
</set>
組合動畫: 融合平移, 縮放, 旋轉, 透明四種動畫, 效果是圖片旋轉著從左上角滾入屏幕, 逐漸變大變清晰.
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000">
<!--平移動畫-->
<translate
android:fromXDelta="50"
android:fromYDelta="-100"
android:toXDelta="0"
android:toYDelta="0"/>
<!--縮放動畫-->
<scale
android:duration="2000"
android:fromXScale="0.0"
android:fromYScale="0.0"
android:toXScale="1.0"
android:toYScale="1.0"/>
<!--旋轉動畫-->
<rotate
android:duration="2000"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="-720"/>
<!--透明動畫-->
<alpha
android:duration="2000"
android:fromAlpha="0.1"
android:toAlpha="1.0"/>
</set>
幀動畫: 特殊動畫, 不斷變換圖片, 模擬動畫效果. animation-list動畫列表, 每個item表示一個圖片, duration是圖片停留時間. oneshot值是true持續(xù)一次, false不斷循環(huán).
<?xml version="1.0" encoding="utf-8"?>
<animation-list
xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<!--循環(huán)顯示三個圖片-->
<item
android:drawable="@drawable/seo_square"
android:duration="250"/>
<item
android:drawable="@drawable/kim_square"
android:duration="250"/>
<item
android:drawable="@drawable/sunny_square"
android:duration="250"/>
</animation-list>
自定義動畫: 重載initialize和applyTransformation方法. initialize初始化動畫; applyTransformation應用轉換, 參數(shù)interpolatedTime表示差值次數(shù).
public class Rotate3dAnimation extends Animation {
private final float mFromDegrees;
private final float mToDegrees;
private final float mCenterX;
private final float mCenterY;
private final float mDepthZ;
private final boolean mReverse;
private Camera mCamera;
public Rotate3dAnimation(
float fromDegrees, float toDegrees,
float centerX, float centerY,
float depthZ, boolean reverse) {
mFromDegrees = fromDegrees;
mToDegrees = toDegrees;
mCenterX = centerX;
mCenterY = centerY;
mDepthZ = depthZ;
mReverse = reverse;
}
@Override public void initialize(int width, int height, int parentWidth, int parentHeight) {
super.initialize(width, height, parentWidth, parentHeight);
mCamera = new Camera();
}
@Override protected void applyTransformation(float interpolatedTime, Transformation t) {
final float fromDegrees = mFromDegrees;
float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime); // 結尾度數(shù)
// 中心點
final float centerX = mCenterX;
final float centerY = mCenterY;
final Camera camera = mCamera;
final Matrix matrix = t.getMatrix();
camera.save(); // 照相機
// Z軸平移
if (mReverse) {
camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
} else {
camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
}
camera.rotateY(degrees); // Y軸旋轉
camera.getMatrix(matrix);
camera.restore();
// View的中心點進行旋轉
matrix.preTranslate(-centerX, -centerY);
matrix.postTranslate(centerX, centerX);
super.applyTransformation(interpolatedTime, t);
}
}
RecyclerList的項也支持動畫式插入.
@Override public void onBindViewHolder(final GridViewHolder holder, final int position) {
// ...
setAnimation(holder.getContainer(), position);
}
private void setAnimation(View viewToAnimate, int position) {
if (position > mLastPosition || mLastPosition == -1) {
Animation animation = AnimationUtils.loadAnimation(mContext, android.R.anim.slide_in_left);
viewToAnimate.startAnimation(animation);
mLastPosition = position;
}
}
屬性動畫
屬性動畫通過變換對象屬性, 實現(xiàn)動畫效果, 對應屬性必須含有set和get方法, 支持調用. 對于自定義的屬性, 則使用Wrapper或插值方式.
屬性動畫僅支持API 11以上版本, 以前版本使用支持庫.
Wrapper: 根據(jù)View的變換屬性, 提供寬度(width)的設置(set)與獲取(get).
private void performWrapperAnimation(final View view, final int start, final int end) {
ViewWrapper vw = new ViewWrapper(view);
ObjectAnimator.ofInt(vw, "width", start, end).setDuration(2000).start(); // 啟動動畫
}
// 視圖包裝, 提供Width的get和set方法
private static class ViewWrapper {
private View mView;
public ViewWrapper(View view) {
mView = view;
}
@SuppressWarnings("unused")
public int getWidth() {
return mView.getLayoutParams().width;
}
@SuppressWarnings("unused")
public void setWidth(int width) {
mView.getLayoutParams().width = width;
mView.requestLayout();
}
}
requestLayout: 當View確定自身不再適合現(xiàn)有區(qū)域時, 調用requestLayout, 要求Parent View重新調用onMeasure和onLayout重新設置當前View的位置.
特別當View的LayoutParams發(fā)生改變時, 并且值還未應用至View上, 這時候適合調用此方法.
invalidate: View本身調用迫使View重繪.
差值: 使用ValueAnimator(屬性動畫), 并設置更新, 添加IntEvaluator(整數(shù)估值器), 漸進地設置View的寬度.
private void performListenerAnimation(final View view, 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 animator) {
// 獲得當前動畫的進度值,整型,1-100之間
int currentValue = (Integer) animator.getAnimatedValue();
// 獲得當前進度占整個動畫過程的比例,浮點型,0-1之間
float fraction = animator.getAnimatedFraction();
// 直接調用整型估值器通過比例計算出寬度,然后再設給Button
view.getLayoutParams().width = mEvaluator.evaluate(fraction, start, end);
view.requestLayout();
}

](http://upload-images.jianshu.io/upload_images/749674-cdf2dd08094b34fa.gif?imageMogr2/auto-orient/strip)
](http://upload-images.jianshu.io/upload_images/749674-a45e2ffca44d4f79.gif?imageMogr2/auto-orient/strip)
});
valueAnimator.setDuration(2000).start();
}
注意LayoutParams的數(shù)值是px像素, 需要dp轉換px.
效果

應用使用動畫, 提升用戶體驗, 但要注意性能. 大量使用圖片可能導致OOM; 循環(huán)動畫無法釋放可能產(chǎn)生內存泄露; 注意px與dp之間的轉換.
OK, that's all! Enjoy it!