Android View動畫和屬性動畫
在應用中, 動畫效果提升用戶體驗, 主要分為 View動畫 和 屬性動畫 . View動畫變換場景圖片效果, 效果包括平移(translate), 縮放(scale), 旋轉(rotate), 透明(alpha); 屬性動畫動態地改變改變屬性, 達到動畫效果.
Animation
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 持續時間; 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持續一次, false不斷循環.
<?xml version="1.0" encoding="utf-8"?>
<animation-list
xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<!--循環顯示三個圖片-->
<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 應用轉換, 參數 interpolatedTime 表示差值次數.
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); // 結尾度數
// 中心點
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;
}
}
屬性動畫
屬性動畫通過變換對象屬性, 實現動畫效果, 對應屬性必須含有set和get方法, 支持調用. 對于自定義的屬性, 則使用 Wrapper 或 插值方式 .
屬性動畫僅支持 API 11 以上版本, 以前版本使用 支持庫 .
Wrapper: 根據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確定自身不再適合現有區域時, 調用requestLayout, 要求Parent View重新調用onMeasure和onLayout重新設置當前View的位置.
特別當View的LayoutParams發生改變時, 并且值還未應用至View上, 這時候適合調用此方法.
invalidate: View本身調用迫使View重繪.
差值: 使用 ValueAnimator (屬性動畫), 并設置更新, 添加 IntEvaluator (整數估值器), 漸進地設置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的數值是px像素, 需要dp轉換px.
效果
效果
應用使用動畫, 提升用戶體驗, 但要注意性能. 大量使用圖片可能導致OOM; 循環動畫無法釋放可能產生內存泄露; 注意px與dp之間的轉換.
來自:http://www.jianshu.com/p/37ccbf95e24c