现在的位置: 首页 > 综合 > 正文

framework 之 Animation

2018年03月31日 ⁄ 综合 ⁄ 共 6151字 ⁄ 字号 评论关闭

一、前言:

        Animation是OS 4.0以前就有的一个动画框架,源代码位于SDK / android / view / animation下,此目录下还有自带实现的几种动画类,和一些Interpolater(插补器),不过,它只实现了基础的动画效果,见UML图。此类是对整个View做了动画效果,但是效率较低,因此在OS4.0 之后,又添加了新的动画框架:Animator。本篇文章只讲Animation,以后会写篇关于Animator的文章。

二、UML图:

图中,显示系统提供了四种动画:透明、旋转、缩放和位移。

三、详细讲解抽象类Animation:

3.1 如何使用Animation

使用它有两种方法:

1. 写一个xml文件,里面定义了一些animation效果,可以是一个效果,也可以是一组(AnimationSet);

2. 继承Animation,自己写个,或者使用系统提供的那四种;

因此,Animation初始化也对应两种方法:

    /**
     * Creates a new animation with a duration of 0ms, the default interpolator, with
     * fillBefore set to true and fillAfter set to false
     */
    public Animation() {
        ensureInterpolator();
    }

    /**
     * Creates a new animation whose parameters come from the specified context and
     * attributes set.
     *
     * @param context the application environment
     * @param attrs the set of attributes holding the animation parameters
     */
    public Animation(Context context, AttributeSet attrs) {
        TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Animation);

        setDuration((long) a.getInt(com.android.internal.R.styleable.Animation_duration, 0));
        setStartOffset((long) a.getInt(com.android.internal.R.styleable.Animation_startOffset, 0));
        
        setFillEnabled(a.getBoolean(com.android.internal.R.styleable.Animation_fillEnabled, mFillEnabled));
        setFillBefore(a.getBoolean(com.android.internal.R.styleable.Animation_fillBefore, mFillBefore));
        setFillAfter(a.getBoolean(com.android.internal.R.styleable.Animation_fillAfter, mFillAfter));

        setRepeatCount(a.getInt(com.android.internal.R.styleable.Animation_repeatCount, mRepeatCount));
        setRepeatMode(a.getInt(com.android.internal.R.styleable.Animation_repeatMode, RESTART));

        setZAdjustment(a.getInt(com.android.internal.R.styleable.Animation_zAdjustment, ZORDER_NORMAL));
        
        setBackgroundColor(a.getInt(com.android.internal.R.styleable.Animation_background, 0));

        setDetachWallpaper(a.getBoolean(com.android.internal.R.styleable.Animation_detachWallpaper, false));

        final int resID = a.getResourceId(com.android.internal.R.styleable.Animation_interpolator, 0);

        a.recycle();

        if (resID > 0) {
            setInterpolator(context, resID);
        }

        ensureInterpolator();
    }

一个是直接调用一个叫ensureInterpolator的方法,另一个是先使用系统默认的一些style,然后,再调用ensureInterpolator,那这个方法到底做了啥呢?我们来看看:

    /**
     * Gurantees that this animation has an interpolator. Will use
     * a AccelerateDecelerateInterpolator is nothing else was specified.
     */
    protected void ensureInterpolator() {
        if (mInterpolator == null) {
            mInterpolator = new AccelerateDecelerateInterpolator();
        }
    }

如果没有设置interpolater,那么,我们就使用一个先加速后减速的插补器,关于插补器,看我另一篇博文:

http://blog.csdn.net/qingye_love/article/details/8859347

3.2 成员属性
主要成员有:

1. mDuration:动画持续时间;

2. mStartOffset:某个动画的开始时间;(一组动画中,可以设置并发,或串行)

3. mFillEnabled,mFillBefore,mFillAfter:动画结束后是否回到初始状态,或者保持结束状态,默认是回到初始状态;

4. mRepeatCount,mRepeatMode:动画是否重复,重复次数,重复模式(从头开始,从头到尾再到头等);

5. mInterpolator:插补器,控制动画的快慢;

3.3 成员方法

动画开始方法:

    public void setStartTime(long startTimeMillis) {
        mStartTime = startTimeMillis;
        mStarted = mEnded = false;
        mCycleFlip = false;
        mRepeated = 0;
        mMore = true;
    }

    /**
     * Convenience method to start the animation the first time
     * {@link #getTransformation(long, Transformation)} is invoked.
     */
    public void start() {
        setStartTime(-1);
    }

    /**
     * Convenience method to start the animation at the current time in
     * milliseconds.
     */
    public void startNow() {
        setStartTime(AnimationUtils.currentAnimationTimeMillis());
    }

start与startNow的区别可能在于,一个有点延迟,一个立马开始。

Animation类中最主要的方法: getTransformation,这个方法只计算已经过了多久,然后调用之前创建的Interpolater来计算速率,并最终调用重载Animation类的applyTransformation方法来完成你想要展现的动画效果,那么我们来看看方法的实现吧:

    /**
     * Gets the transformation to apply at a specified point in time. Implementations of this
     * method should always replace the specified Transformation or document they are doing
     * otherwise.
     *
     * @param currentTime Where we are in the animation. This is wall clock time.
     * @param outTransformation A transformation object that is provided by the
     *        caller and will be filled in by the animation.
     * @return True if the animation is still running
     */
    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) {
            normalizedTime = ((float) (currentTime - (mStartTime + startOffset))) /
                    (float) duration;
        } else {
            // time is a step-change with a zero duration
            normalizedTime = currentTime < mStartTime ? 0.0f : 1.0f;
        }

        final boolean expired = normalizedTime >= 1.0f;
        mMore = !expired;

        if (!mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f);

       // 前面的部分是计算normalizedTime,这里开始才是调用执行
        if ((normalizedTime >= 0.0f || mFillBefore) && (normalizedTime <= 1.0f || mFillAfter)) {
            if (!mStarted) {
                if (mListener != null) {
                    mListener.onAnimationStart(this);
                }
                mStarted = true;
                if (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);
            applyTransformation(interpolatedTime, outTransformation);
        }
        // 完成了applyTransformation的调用,后面计算动画是否循环

        if (expired) {
            if (mRepeatCount == mRepeated) {
                if (!mEnded) {
                    mEnded = true;
                    guard.close();
                    if (mListener != null) {
                        mListener.onAnimationEnd(this);
                    }
                }
            } else {
                if (mRepeatCount > 0) {
                    mRepeated++;
                }

                if (mRepeatMode == REVERSE) {
                    mCycleFlip = !mCycleFlip;
                }

                mStartTime = -1;
                mMore = true;

                if (mListener != null) {
                    mListener.onAnimationRepeat(this);
                }
            }
        }

        if (!mMore && mOneMoreTime) {
            mOneMoreTime = false;
            return true;
        }

        return mMore;
    }

这个方法中,还有一个成员是mListener,它的类型是AnimationListener,在这个Animation类的末尾,定义了AnimationListener接口,继承Animation类的子类可以使用此接口,来监听比如动画开始时要做保存工作,动画结束时要做清除及恢复工作等。

    /**
     * <p>An animation listener receives notifications from an animation.
     * Notifications indicate animation related events, such as the end or the
     * repetition of the animation.</p>
     */
    public static interface AnimationListener {
        /**
         * <p>Notifies the start of the animation.</p>
         *
         * @param animation The started animation.
         */
        void onAnimationStart(Animation animation);

        /**
         * <p>Notifies the end of the animation. This callback is not invoked
         * for animations with repeat count set to INFINITE.</p>
         *
         * @param animation The animation which reached its end.
         */
        void onAnimationEnd(Animation animation);

        /**
         * <p>Notifies the repetition of the animation.</p>
         *
         * @param animation The animation which was repeated.
         */
        void onAnimationRepeat(Animation animation);
    }

四、总结:

Animation类的讲解,只是一个抛砖引玉,让大家在继承或使用其子类时,能够更好的去理解其原理,正如本文开头所说,在Android OS4.0之后,又出现了一个新的叫Animator类,之所以新添加了一个动画框架,其原因:

1. Animation能力有限,即便是将4种效果组合来用,也无法达到某些高级特效的效果;

2. Animation需要对整个view进行动画,这也导致其性能较低;

而Animator弥补了这些,因此争取有空时,将Animator也讲解一下。

写的不好的地方,也请大家指出来,谢谢!

抱歉!评论已关闭.