zoukankan      html  css  js  c++  java
  • View动画和属性动画

    在应用中, 动画效果提升用户体验, 主要分为View动画和属性动画. View动画变换场景图片效果, 效果包括平移(translate), 缩放(scale), 旋转(rotate), 透明(alpha); 属性动画动态地改变改变属性, 达到动画效果. 本文包含源码.

    Animation

    本文源码的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持续时间; 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>

    自定义动画: 重载initializeapplyTransformation方法. 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](https://user-gold-cdn.xitu.io/2017/1/4/5cba3a11357c16ea9129f9c7a6b9f1cc)
    ](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之间的转换.

    OK, that's all! Enjoy it!

  • 相关阅读:
    mysql in 中使用子查询,会不使用索引而走全表扫描
    java集合之hashMap,初始长度,高并发死锁,java8 hashMap做的性能提升
    简要了解web安全之sql注入
    java之JVM学习--简单了解GC算法
    java之JVM学习--简单理解编译和运行的过程之概览
    java之JVM学习--基本机构
    JDK,JRE,JVM 关系和概念
    SpringAOP源码解析
    数据结构——实现list
    由数据库练习浅析子查询和链接查询
  • 原文地址:https://www.cnblogs.com/wangfeng520/p/6249832.html
Copyright © 2011-2022 走看看