(二十二)Animator 源码分析

版权声明:本文为博主原创文章,未经博主允许不得转载。

本文纯个人学习笔记,由于水平有限,难免有所出错,有发现的可以交流一下。

这是是根据 API 25 进行 ObjectAnimator 的使用代码分析。

    public void startAnimator(View view){
        ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView, "translationX", 0f, 200f);
        objectAnimator.setDuration(500);
        objectAnimator.start();
    }

一、ofFloat

ObjectAnimator 的 ofFloat:

    public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
        ObjectAnimator anim = new ObjectAnimator(target, propertyName);
        anim.setFloatValues(values);
        return anim;
    }

在这里,他先 new 了一个 ObjectAnimator,跟进去查看一下:调用了 setTarget 和 setPropertyName 方法。

  private ObjectAnimator(Object target, String propertyName) {
        setTarget(target);
        setPropertyName(propertyName);
    }

很明显,setTarget 设置的是该属性动画的执行对象是谁,setPropertyName 设置要执行的是什么属性。

ObjectAnimator 的 setTarget:

    public void setTarget(@Nullable Object target) {
        final Object oldTarget = getTarget();
        if (oldTarget != target) {
            if (isStarted()) {
                cancel();
            }
            mTarget = target == null ? null : new WeakReference<Object>(target);
            // New target should cause re-initialization prior to starting
            mInitialized = false;
        }
    }

在 setTarget 中把要执行动画的对象存在成员变量 mTarget 中,这边采用的是弱引用,可以有效的避免内存泄漏。同样的,在 setPropertyName 中把执行动画的属性存在成员变量 mProperty 中。

继续 ofFloat 往下,调用了 ObjectAnimator 的 setFloatValues 方法。

ObjectAnimator 的 setFloatValues:

    public void setFloatValues(float... values) {
        if (mValues == null || mValues.length == 0) {
            // No values yet - this animator is being constructed piecemeal. Init the values with
            // whatever the current propertyName is
            if (mProperty != null) {
                setValues(PropertyValuesHolder.ofFloat(mProperty, values));
            } else {
                setValues(PropertyValuesHolder.ofFloat(mPropertyName, values));
            }
        } else {
            super.setFloatValues(values);
        }
    }

正常情况下, mValues 是不会为空的,走 else,调用 ValueAnimator 的 setFloatValues 方法。

ValueAnimator 的 setFloatValues:

   public void setFloatValues(float... values) {
        if (values == null || values.length == 0) {
            return;
        }
        if (mValues == null || mValues.length == 0) {
            setValues(PropertyValuesHolder.ofFloat("", values));
        } else {
            PropertyValuesHolder valuesHolder = mValues[0];
            valuesHolder.setFloatValues(values);
        }
        // New property/values/target should cause re-initialization prior to starting
        mInitialized = false;
    }

在 ValueAnimator 的 setFloatValues 中,使用了一个 PropertyValuesHolder 这个类,第一次调用 mValues 是空的,调用 PropertyValuesHolder.ofFloat("", values)。一直点下去,最终也跟 else 一样调用了 PropertyValuesHolder 的 setFloatValues 方法。

PropertyValuesHolder 的 setFloatValues:

    public void setFloatValues(float... values) {
	    //设置值类型
        mValueType = float.class;
        //设置关键帧
        mKeyframes = KeyframeSet.ofFloat(values);
    }

直接设置值类型 mValueType 为 float 类型,可以猜想,如果是 setIntValues ,那值类型 mValueType 设置为 int。

mKeyframes 是存放关键帧,关键帧在初始时候传入属性值变化的范围(下放代码 0f 和 200f 即关键帧)

ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView, "translationX", 0f, 200f);

当传入多个的时候,关键帧也将变成多个。下方关键帧有 4 个,变化区间有三个,如果动画执行时间是 300ms,则每个区间的执行时间将均匀分配为 100ms。(为什么平均分配,后面看到再提)

ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView, "translationX", 0f, 200f, 500f, 400f);

KeyframeSet 的 ofFloat:

    public static KeyframeSet ofFloat(float... values) {
        boolean badValue = false;
        int numKeyframes = values.length;
        //FloatKeyframe 是一个接口,在这 new 了一个 FloatKeyframe 数组

        //关键帧只有一个的时候,默认加一个 0f
        if (numKeyframes == 1) {
            keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f);
            keyframes[1] = (FloatKeyframe) Keyframe.ofFloat(1f, values[0]);
            if (Float.isNaN(values[0])) {
                badValue = true;
            }
        } else {
            keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f, values[0]);
            for (int i = 1; i < numKeyframes; ++i) {
	            //(float) i / (numKeyframes - 1) 则是为了将时间均分
                keyframes[i] =
                        (FloatKeyframe) Keyframe.ofFloat((float) i / (numKeyframes - 1), values[i]);
                if (Float.isNaN(values[i])) {
                    badValue = true;
                }
            }
        }
        if (badValue) {
            Log.w("Animator", "Bad value (NaN) in float animator");
        }
        return new FloatKeyframeSet(keyframes);
    }

在这边,判断关键帧的个数,当关键帧只有一个的时候,添加一个 0f 的关键帧,所以,下面两行代码效果是一致的:

ObjectAnimator.ofFloat(view,"translationX", 1f);

ObjectAnimator.ofFloat(view,"translationX", 0f, 1f);

中间先不管,最终是返回了一个 new FloatKeyframeSet(keyframes),在这里直接调用 super(keyframes), FloatKeyframeSet 的父类是 KeyframeSet ,即又调回到 KeyframeSet 的构造方法。

KeyframeSet 的构造方法:

    public KeyframeSet(Keyframe... keyframes) {
        mNumKeyframes = keyframes.length;
        // immutable list
        //保存所有帧
        mKeyframes = Arrays.asList(keyframes);
        //设置第一帧
        mFirstKeyframe = keyframes[0];
        //设置最后一帧
        mLastKeyframe = keyframes[mNumKeyframes - 1];
        mInterpolator = mLastKeyframe.getInterpolator();
    }

顺便查看一下 KeyframeSet 的其他成员变量,可以发现,KeyframeSet 还保存有估值器和插值器。

总结: ObjectAnimator 的 ofFloat 方法主要做一些初始化操作,新建了一个 ObjectAnimator 对象,保存了要执行动画的对象和属性,并对关键帧进行了解析。

二、start

1.回调

接下来继续看一下 ObjectAnimator 的 start 方法。

ObjectAnimator 的 start:

    public void start() {
        AnimationHandler.getInstance().autoCancelBasedOn(this);
        if (DBG) {
            Log.d(LOG_TAG, "Anim target, duration: " + getTarget() + ", " + getDuration());
            for (int i = 0; i < mValues.length; ++i) {
                PropertyValuesHolder pvh = mValues[i];
                Log.d(LOG_TAG, "   Values[" + i + "]: " +
                    pvh.getPropertyName() + ", " + pvh.mKeyframes.getValue(0) + ", " +
                    pvh.mKeyframes.getValue(1));
            }
        }
        super.start();
    }

中间一些处理忽略,最终调用了 super.start(),ObjectAnimator 的父类是 ValueAnimator,即调用了 ValueAnimator的 start。

ValueAnimator 的 start:

    private void start(boolean playBackwards) {
        if (Looper.myLooper() == null) {
            throw new AndroidRuntimeException("Animators may only be run on Looper threads");
        }
        mReversing = playBackwards;
        // Special case: reversing from seek-to-0 should act as if not seeked at all.
        if (playBackwards && mSeekFraction != -1 && mSeekFraction != 0) {
            if (mRepeatCount == INFINITE) {
                // Calculate the fraction of the current iteration.
                float fraction = (float) (mSeekFraction - Math.floor(mSeekFraction));
                mSeekFraction = 1 - fraction;
            } else {
                mSeekFraction = 1 + mRepeatCount - mSeekFraction;
            }
        }
        mStarted = true;
        mPaused = false;
        mRunning = false;
        mAnimationEndRequested = false;
        // Resets mLastFrameTime when start() is called, so that if the animation was running,
        // calling start() would put the animation in the
        // started-but-not-yet-reached-the-first-frame phase.
        mLastFrameTime = 0;
        AnimationHandler animationHandler = AnimationHandler.getInstance();
        animationHandler.addAnimationFrameCallback(this, (long) (mStartDelay * sDurationScale));

        if (mStartDelay == 0 || mSeekFraction >= 0) {
            // If there's no start delay, init the animation and notify start listeners right away
            // to be consistent with the previous behavior. Otherwise, postpone this until the first
            // frame after the start delay.
            startAnimation();
            if (mSeekFraction == -1) {
                // No seek, start at play time 0. Note that the reason we are not using fraction 0
                // is because for animations with 0 duration, we want to be consistent with pre-N
                // behavior: skip to the final value immediately.
                setCurrentPlayTime(0);
            } else {
                setCurrentFraction(mSeekFraction);
            }
        }
    }

这里使用了一个 animationHandler,通过广播的机制由底层进行回调,每 16ms 进行一次回调。(再下去就比较底层了,涉及到垂直刷新,不继续了)

继续查看 AnimationHandler 的 addAnimationFrameCallback 方法。

AnimationHandler 的 addAnimationFrameCallback:

    public void addAnimationFrameCallback(final AnimationFrameCallback callback, long delay) {
        if (mAnimationCallbacks.size() == 0) {
	        //再分析下去比较复杂,总之广播接收到会调用 mFrameCallback。
            getProvider().postFrameCallback(mFrameCallback);
        }
        //保存回调
        if (!mAnimationCallbacks.contains(callback)) {
            mAnimationCallbacks.add(callback);
        }

        if (delay > 0) {
            mDelayedCallbackStartTime.put(callback, (SystemClock.uptimeMillis() + delay));
        }
    }

我们看一下变量 mFrameCallback,回调的时候调用了 doAnimationFrame 方法。getProvider().getFrameTime() 获取的当前动画执行的真正时间。

    private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
        @Override
        public void doFrame(long frameTimeNanos) {
            doAnimationFrame(getProvider().getFrameTime());
            if (mAnimationCallbacks.size() > 0) {
                getProvider().postFrameCallback(this);
            }
        }
    };

AnimationHandler 的 doAnimationFrame:

    private void doAnimationFrame(long frameTime) {
        int size = mAnimationCallbacks.size();
        long currentTime = SystemClock.uptimeMillis();
        for (int i = 0; i < size; i++) {
            final AnimationFrameCallback callback = mAnimationCallbacks.get(i);
            if (callback == null) {
                continue;
            }
            if (isCallbackDue(callback, currentTime)) {
	            //循环遍历调用所有回调
                callback.doAnimationFrame(frameTime);
                if (mCommitCallbacks.contains(callback)) {
                    getProvider().postCommitCallback(new Runnable() {
                        @Override
                        public void run() {
                            commitAnimationFrame(callback, getProvider().getFrameTime());
                        }
                    });
                }
            }
        }
        cleanUpList();
    }

这里的 callback 是由 ValueAnimator 中传递过来的 this,即 ValueAnimator 本身。ValueAnimator 的 doAnimationFrame 方法会调用 startAnimation 方法,跟 ObjectAnimator 的 start 一样。

2.反射方法

继续 ValueAnimator 的 start 方法,接下去直接调用 startAnimation() 启动动画,

ValueAnimator 的 startAnimation :

    private void startAnimation() {
        if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
            Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, getNameForTrace(),
                    System.identityHashCode(this));
        }

        mAnimationEndRequested = false;
        initAnimation();
        mRunning = true;
        if (mSeekFraction >= 0) {
            mOverallFraction = mSeekFraction;
        } else {
            mOverallFraction = 0f;
        }
        if (mListeners != null) {
            notifyStartListeners();
        }
    }

调用 initAnimation() 进行一些初始化操作,这边要注意一点的是,我们在这边分析的 ObjectAnimator 的源码,ObjectAnimator 有对 initAnimation 方法进行重写。

ObjectAnimator 的 initAnimation :

    void initAnimation() {
        if (!mInitialized) {
            // mValueType may change due to setter/getter setup; do this before calling super.init(),
            // which uses mValueType to set up the default type evaluator.
            final Object target = getTarget();
            if (target != null) {
                final int numValues = mValues.length;
                for (int i = 0; i < numValues; ++i) {
	                //mValues 是父类 ValueAnimator 的属性,是 PropertyValuesHolder 
                    mValues[i].setupSetterAndGetter(target);
                }
            }
            super.initAnimation();
        }
    }

ObjectAnimator 的 initAnimation 调用了 PropertyValuesHolder 的 setupSetterAndGetter 方法。

PropertyValuesHolder 的 setupSetterAndGetter:

 void setupSetterAndGetter(Object target) {
        ...
            Class targetClass = target.getClass();
            if (mSetter == null) {
                setupSetter(targetClass);
            }
        ...
    }

PropertyValuesHolder 的 setupSetter:

    void setupSetter(Class targetClass) {
        Class<?> propertyType = mConverter == null ? mValueType : mConverter.getTargetType();
        //传入 set,反射生成 set 方法。
        mSetter = setupSetterOrGetter(targetClass, sSetterPropertyMap, "set", propertyType);
    }

PropertyValuesHolder 的 setupSetterOrGetter:

   private Method setupSetterOrGetter(Class targetClass,
            HashMap<Class, HashMap<String, Method>> propertyMapMap,
            String prefix, Class valueType) {
			...
                setterOrGetter = getPropertyFunction(targetClass, prefix, valueType);
            ...
        }
        return setterOrGetter;
    }

PropertyValuesHolder 的 getPropertyFunction:

 private Method getPropertyFunction(Class targetClass, String prefix, Class valueType) {
        // TODO: faster implementation...
        Method returnVal = null;
        String methodName = getMethodName(prefix, mPropertyName);
        Class args[] = null;
        if (valueType == null) {
            try {
                returnVal = targetClass.getMethod(methodName, args);
            } catch (NoSuchMethodException e) {
                // Swallow the error, log it later
            }
        } else {
			...
		}
        return returnVal;
    }

PropertyValuesHolder 的 getPropertyFunction 最终通过反射生产对应的 set 或 get 方法并返回。

在这边顺便提一下 getMethodName 方法。

PropertyValuesHolder 的 getMethodName:

    static String getMethodName(String prefix, String propertyName) {
        if (propertyName == null || propertyName.length() == 0) {
            // shouldn't get here
            return prefix;
        }
        char firstLetter = Character.toUpperCase(propertyName.charAt(0));
        String theRest = propertyName.substring(1);
        return prefix + firstLetter + theRest;
    }

getMethodName 方法对传入的方法名进行首字母修改为大写处理,所以在传属性的时候,首字母大小写是没有影响的。下方两行代码效果一样:

    ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView, "translationX", 0f, 200f);

    ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView, "TranslationX", 0f, 200f);

ObjectAnimator 的 initAnimation 在最后调用了 super.initAnimation(),即 ValueAnimator 的 initAnimation 方法。

ValueAnimator 的 initAnimation :

    void initAnimation() {
        if (!mInitialized) {
            int numValues = mValues.length;
            for (int i = 0; i < numValues; ++i) {
                mValues[i].init();
            }
            mInitialized = true;
        }
    }

mValues[i].init() 调用了 PropertyValuesHolder 的 init,在这里进行了估值器的设置。

总结: 到这里,PropertyValuesHolder 的成员变量 mSetter 为对应属性的 set 方法。

3.方法的调用

再次回到 ValueAnimator 的 start 继续向下。

ValueAnimator 的 start :

            if (mSeekFraction == -1) {
                // No seek, start at play time 0. Note that the reason we are not using fraction 0
                // is because for animations with 0 duration, we want to be consistent with pre-N
                // behavior: skip to the final value immediately.
                setCurrentPlayTime(0);
            } else {
                setCurrentFraction(mSeekFraction);
            }

ValueAnimator 的 setCurrentPlayTime :

    public void setCurrentPlayTime(long playTime) {
        float fraction = mDuration > 0 ? (float) playTime / mDuration : 1;
        setCurrentFraction(fraction);
    }

所以,ObjectAnimator 的 start 最终调用到了 setCurrentFraction 方法,传入的是动画执行的的百分比。在 setCurrentFraction 方法里面调用了 animateValue 方法。注意,ValueAnimator 也重写了该方法。

ObjectAnimator 的 animateValue :

    void animateValue(float fraction) {
        final Object target = getTarget();
        if (mTarget != null && target == null) {
            // We lost the target reference, cancel and clean up. Note: we allow null target if the
            /// target has never been set.
            cancel();
            return;
        }

        super.animateValue(fraction);
        int numValues = mValues.length;
        for (int i = 0; i < numValues; ++i) {
            mValues[i].setAnimatedValue(target);
        }
    }

ObjectAnimator 的 animateValue 调用了 super.animateValue(fraction), 在这里进行了插值器的使用。
最后调用了 mValues[i].setAnimatedValue(target),即 PropertyValuesHolder 的 setAnimatedValue 方法。
PropertyValuesHolder 的 setAnimatedValue:

    void setAnimatedValue(Object target) {
        if (mProperty != null) {
            mProperty.set(target, getAnimatedValue());
        }
        if (mSetter != null) {
            try {
                mTmpValueArray[0] = getAnimatedValue();
                mSetter.invoke(target, mTmpValueArray);
            } catch (InvocationTargetException e) {
                Log.e("PropertyValuesHolder", e.toString());
            } catch (IllegalAccessException e) {
                Log.e("PropertyValuesHolder", e.toString());
            }
        }
    }

在这里进行前面反射的方法的调用,即我们设置的属性的 set 方法的调用,每次底层回调都会进行一次重新调用改属性的 set 方法进行设置,从而达到动画的效果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值