Android View動畫和屬性動畫

gucheng_bw 7年前發布 | 7K 次閱讀 安卓開發 Android開發 移動開發

在應用中, 動畫效果提升用戶體驗, 主要分為 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();
        }
![
![
![ezgif.com-b9f6ca81b1.gif](http://upload-images.jianshu.io/upload_images/749674-2b7e12f82fdcae62.gif?imageMogr2/auto-orient/strip)
](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

 

 本文由用戶 gucheng_bw 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!