美文网首页
属性动画(ObjectAnimator)

属性动画(ObjectAnimator)

作者: 明朗__ | 来源:发表于2017-03-01 00:51 被阅读3782次
    1. 属性动画的集成关系


      Paste_Image.png
    2. 看一段属性动画的使用代码
    ObjectAnimator animator=ObjectAnimator.ofFloat(image,"rotationX",0f,360f);
            animator.setDuration(2000);//执行时间
            animator.setInterpolator(new LinearInterpolator());//插值器
            animator.setRepeatCount(-1);//-1 代表无限循环执行
            animator.start();
    
    1. 跟进ObjectAnimator.ofFloat(image,"rotationX",0f,360f)
    public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
            ObjectAnimator anim = new ObjectAnimator(target, propertyName);
            anim.setFloatValues(values);
            return anim;
        }
    
    1. 继续进入anim.setFloatValues(values);
     @Override
        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);
            }
        }
    
    1. 进入PropertyValuesHolder.ofFloat(mPropertyName, values)
    public static PropertyValuesHolder ofFloat(String propertyName, float... values) {
            return new FloatPropertyValuesHolder(propertyName, values);
        }
    

    这里出现了 PropertyValuesHolder 那么这个类是干嘛的呢?

    PropertyValuesHolder:顾名思义,就是属性值持有者,它保存了动画过程中所需要操作的属性和对应的值,我们通过ofFloat(Object target, String propertyName, float… values)构造的动画,ofFloat()的内部实现其实就是将传进来的参数封装成PropertyValuesHolder实例来保存动画状态。在封装成PropertyValuesHolder实例以后,后面的操作也是以PropertyValuesHolder为主的

    1. 我们看到返回一个new FloatPropertyValuesHolder(propertyName, values) 进入构造方法
            public FloatPropertyValuesHolder(String propertyName, float... values) {
                super(propertyName);
                setFloatValues(values);
            }
    
    //进入  super(propertyName) 看到只是跟PropertyValuesHolder的成员变量赋值
    private PropertyValuesHolder(String propertyName) {
            mPropertyName = propertyName;
        }
    
    1. 进入 setFloatValues(values)
    @Override
            public void setFloatValues(float... values) {
                super.setFloatValues(values);
                mFloatKeyframes = (Keyframes.FloatKeyframes) mKeyframes;
            }
    
    //进入super.setFloatValues(values);
      public void setFloatValues(float... values) {
            mValueType = float.class;
            mKeyframes = KeyframeSet.ofFloat(values);
        }
    

    KeyframeSet.ofFloat(values);
    Keyframe:意为关键帧,设置了关键帧后,动画就可以在各个关键帧之间平滑过渡的,一个关键帧必须包含两个原素,第一时间点,第二位置,即这个关键帧是表示的是某个物体在哪个时间点应该在哪个位置上。fraction表示当前进度,value表示当前位置。

    1. 我们进入KeyframeSet.ofFloat(values)
    public static KeyframeSet ofFloat(float... values) {
    //这里的values 参数就是我们所传递动画执行参数比如:
    //ObjectAnimator.ofFloat(image,"rotationX",0f,360f);中的0f ,360f
            boolean badValue = false;
            int numKeyframes = values.length;
    //生成最小2个长度大小的数组
            FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes,2)];
    //单我们传递的参数只有一个的时候
            if (numKeyframes == 1) {
              //设置默认数组的元素的一个为0f
                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) {
                    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");
            }
            //将生成的数组添加到List集合
            return new FloatKeyframeSet(keyframes);
        }
    
    1. 接上一步进入new FloatKeyframeSet(keyframes);构造函数
    public FloatKeyframeSet(FloatKeyframe... keyframes) {
            super(keyframes);
        }
    
    //在进入super(keyframes) 父类 KeyframeSet
    class KeyframeSet implements Keyframes {
        int mNumKeyframes;
        Keyframe mFirstKeyframe;
        Keyframe mLastKeyframe;
        TimeInterpolator mInterpolator; // only used in the 2-keyframe case
        List<Keyframe> mKeyframes; // only used when there are not 2 keyframes
        TypeEvaluator mEvaluator;
        public KeyframeSet(Keyframe... keyframes) {
            mNumKeyframes = keyframes.length;
            // 将数组添加mKeyframes集合中 里面保存的是动画每的一帧
            mKeyframes = Arrays.asList(keyframes);
            mFirstKeyframe = keyframes[0];
            mLastKeyframe = keyframes[mNumKeyframes - 1];
            mInterpolator = mLastKeyframe.getInterpolator();
        }
    

    由上可以看出:
    PropertyValuesHolder 它保存了动画过程中所需要操作的属性和对应的值 同时持有KeyframeSet.ofFloat(values)得到动画每一帧的集合

    1. 我去再去属性动画的其他属性设置看看
    //设置执行时间
    @Override
        @NonNull
        public ObjectAnimator setDuration(long duration) {
            super.setDuration(duration);
            return this;
        }
    //进入super.setDuration(duration);
     @Override
        public ValueAnimator setDuration(long duration) {
            if (duration < 0) {
                throw new IllegalArgumentException("Animators cannot have negative duration: " +
                        duration);
            }
            mUnscaledDuration = duration;
            updateScaledDuration();
            return this;
        }
        //设置执行时间 函数 sDurationScale=1.0f
        private void updateScaledDuration() {
            mDuration = (long)(mUnscaledDuration * sDurationScale);
        }
    
    //设置插值器
    @Override
        public void setInterpolator(TimeInterpolator value) {
            if (value != null) {
                mInterpolator = value;
            } else {
              //如果为空 就使用默认的插值器 线性
                mInterpolator = new LinearInterpolator();
            }
        }
    
    1. 最后我们来关注重点 start()方法
     @Override
        public void start() {
            // See if any of the current active/pending animators need to be canceled
            AnimationHandler handler = sAnimationHandler.get();
            if (handler != null) {
                int numAnims = handler.mAnimations.size();
                for (int i = numAnims - 1; i >= 0; i--) {
                    if (handler.mAnimations.get(i) instanceof ObjectAnimator) {
                        ObjectAnimator anim = (ObjectAnimator) handler.mAnimations.get(i);
                        if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {
                            anim.cancel();
                        }
                    }
                }
                numAnims = handler.mPendingAnimations.size();
                for (int i = numAnims - 1; i >= 0; i--) {
                    if (handler.mPendingAnimations.get(i) instanceof ObjectAnimator) {
                        ObjectAnimator anim = (ObjectAnimator) handler.mPendingAnimations.get(i);
                        if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {
                            anim.cancel();
                        }
                    }
                }
                numAnims = handler.mDelayedAnims.size();
                for (int i = numAnims - 1; i >= 0; i--) {
                    if (handler.mDelayedAnims.get(i) instanceof ObjectAnimator) {
                        ObjectAnimator anim = (ObjectAnimator) handler.mDelayedAnims.get(i);
                        if (anim.mAutoCancel && hasSameTargetAndProperties(anim)) {
                            anim.cancel();
                        }
                    }
                }
            }
            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();**调用父类的start()方法
     @Override
        public void start() {
            start(false);
        }
    
    //在接着跟进
    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;
            // 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();
            //这里每隔16毫秒会回调一次该回调方法 这里有一个this 
            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);
                }
            }
        }
    
    Paste_Image.png
    1. 上面我们看到 addAnimationFrameCallback()中传递了一个this 说明ValueAnimator也实现了该接口 且是循环的不断调用该抽象回调方法


      Paste_Image.png

      果然实现了该接口 我们去看看该接口有什么抽象方法

    //该抽象方法有2个 
     interface AnimationFrameCallback {
            void doAnimationFrame(long frameTime);
            void commitAnimationFrame(long frameTime);
        }
    
    //抽象方法的实现
     * Processes a frame of the animation, adjusting the start time if needed.
         *
         * @param frameTime The frame time.
         * @return true if the animation has ended.
         * @hide
         */
    //参数为绘制一帧的时间(每隔16毫秒调用一次) 监听手机发出的Vsync信号 
        public final void doAnimationFrame(long frameTime) {
            AnimationHandler handler = AnimationHandler.getInstance();
            if (mLastFrameTime == 0) {
                // First frame
                handler.addOneShotCommitCallback(this);
                if (mStartDelay > 0) {
                    startAnimation();
                }
                if (mSeekFraction < 0) {
                    mStartTime = frameTime;
                } else {
                    long seekTime = (long) (getScaledDuration() * mSeekFraction);
                    mStartTime = frameTime - seekTime;
                    mSeekFraction = -1;
                }
                mStartTimeCommitted = false; // allow start time to be compensated for jank
            }
            mLastFrameTime = frameTime;
            if (mPaused) {
                mPauseTime = frameTime;
                handler.removeCallback(this);
                return;
            } else if (mResumed) {
                mResumed = false;
                if (mPauseTime > 0) {
                    // Offset by the duration that the animation was paused
                    mStartTime += (frameTime - mPauseTime);
                    mStartTimeCommitted = false; // allow start time to be compensated for jank
                }
                handler.addOneShotCommitCallback(this);
            }
            final long currentTime = Math.max(frameTime, mStartTime);
            boolean finished = animateBasedOnTime(currentTime);
            if (finished) {
                endAnimation();
            }
        }
    
    1. boolean finished = animateBasedOnTime(currentTime);将相对时间转换为绝对时间的百分比
    boolean animateBasedOnTime(long currentTime) {
            boolean done = false;
            if (mRunning) {
                final long scaledDuration = getScaledDuration();
                //(总时间-开始时间)/运行的时间 得出运行百分比
                final float fraction = scaledDuration > 0 ?
                        (float)(currentTime - mStartTime) / scaledDuration : 1f;
                final float lastFraction = mOverallFraction;
                final boolean newIteration = (int) fraction > (int) lastFraction;
                final boolean lastIterationFinished = (fraction >= mRepeatCount + 1) &&
                        (mRepeatCount != INFINITE);
                if (scaledDuration == 0) {
                    // 0 duration animator, ignore the repeat count and skip to the end
                    done = true;
                } else if (newIteration && !lastIterationFinished) {
                    // Time to repeat
                    if (mListeners != null) {
                        //mListeners监听集合
                        int numListeners = mListeners.size();
                        for (int i = 0; i < numListeners; ++i) {
                          //观察者模式 监听回调 动画重复执行
                            mListeners.get(i).onAnimationRepeat(this);
                        }
                    }
                } else if (lastIterationFinished) {
                    done = true;
                }
                mOverallFraction = clampFraction(fraction);
                float currentIterationFraction = getCurrentIterationFraction(mOverallFraction);
                //这里调用ObjectAnimator子类的animateValue()函数
                animateValue(currentIterationFraction);
            }
            return done;
        }
    
    1. 进入ObjectAnimator子类的animateValue()
    @CallSuper
        @Override
        //参数执行百分比(0-1)
        void animateValue(float fraction) {
            final Object target = getTarget();
            if (mTarget != null && target == null) {
                // We lost the target reference, cancel and clean up.
                cancel();
                return;
            }
            //调用父类animateValue()方法
            super.animateValue(fraction);
            int numValues = mValues.length;
            for (int i = 0; i < numValues; ++i) {
                  //这里设置View的宽高 target代表动画控件
                mValues[i].setAnimatedValue(target);
            }
        }
    
    //进入父类的animateValue();
    @CallSuper
        void animateValue(float fraction) {
          //调用插值器的方法 (策略模式) 得到插值器运行百分比
            fraction = mInterpolator.getInterpolation(fraction);
          //赋值成员变量
            mCurrentFraction = fraction;
            int numValues = mValues.length;
            for (int i = 0; i < numValues; ++i) {
                //调用PropertyValuesHolder 的calculateValue();
                mValues[i].calculateValue(fraction);
            }
            if (mUpdateListeners != null) {
                int numListeners = mUpdateListeners.size();
                for (int i = 0; i < numListeners; ++i) {
                  //动画更新监听回调回调
                    mUpdateListeners.get(i).onAnimationUpdate(this);
                }
            }
        }
    
    //抽象插值器
    public interface TimeInterpolator {
        float getInterpolation(float input);
    }
    
    //PropertyValuesHolder 的calculateValue
     void calculateValue(float fraction) {
            Object value = mKeyframes.getValue(fraction);
            //返回执行动画的百分比
            mAnimatedValue = mConverter == null ? value : mConverter.convert(value);
        }
    
    //接上面mAnimatedValue返回后回到 ObjectAnimator的 animateValue()继续执行来到
     int numValues = mValues.length;
            for (int i = 0; i < numValues; ++i) {
                  //这里设置View的宽高 target代表动画控件
                mValues[i].setAnimatedValue(target);
            }
    
    //进入 mValues[i].setAnimatedValue(target);
    void setAnimatedValue(Object target) {
            if (mProperty != null) {
                mProperty.set(target, getAnimatedValue());
            }
            if (mSetter != null) {
                try {
                    mTmpValueArray[0] = getAnimatedValue();
                    //mSetter是在startAnimator()初始化的时候通过反射赋值
                    //invoke 重绘 动画view
                    mSetter.invoke(target, mTmpValueArray);
                } catch (InvocationTargetException e) {
                    Log.e("PropertyValuesHolder", e.toString());
                } catch (IllegalAccessException e) {
                    Log.e("PropertyValuesHolder", e.toString());
                }
            }
        }
    
    //其中mSetter 是在动画初始化的时候赋值ObjectAnimator
     @CallSuper
        @Override
        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[i].setupSetterAndGetter(target);
                    }
                }
                super.initAnimation();
            }
        }
    
    //其中mValues[i].setupSetterAndGetter(target); PropertyValuesHolder
    void setupSetterAndGetter(Object target) {
            mKeyframes.invalidateCache();
            if (mProperty != null) {
                // check to make sure that mProperty is on the class of target
                try {
                    Object testValue = null;
                    List<Keyframe> keyframes = mKeyframes.getKeyframes();
                    int keyframeCount = keyframes == null ? 0 : keyframes.size();
                    for (int i = 0; i < keyframeCount; i++) {
                        Keyframe kf = keyframes.get(i);
                        if (!kf.hasValue() || kf.valueWasSetOnStart()) {
                            if (testValue == null) {
                                testValue = convertBack(mProperty.get(target));
                            }
                            kf.setValue(testValue);
                            kf.setValueWasSetOnStart(true);
                        }
                    }
                    return;
                } catch (ClassCastException e) {
                    Log.w("PropertyValuesHolder","No such property (" + mProperty.getName() +
                            ") on target object " + target + ". Trying reflection instead");
                    mProperty = null;
                }
            }
            // We can't just say 'else' here because the catch statement sets mProperty to null.
            if (mProperty == null) {
                Class targetClass = target.getClass();
                if (mSetter == null) {
                    setupSetter(targetClass);
                }
                List<Keyframe> keyframes = mKeyframes.getKeyframes();
                int keyframeCount = keyframes == null ? 0 : keyframes.size();
                for (int i = 0; i < keyframeCount; i++) {
                    Keyframe kf = keyframes.get(i);
                    if (!kf.hasValue() || kf.valueWasSetOnStart()) {
                        if (mGetter == null) {
                            setupGetter(targetClass);
                            if (mGetter == null) {
                                // Already logged the error - just return to avoid NPE
                                return;
                            }
                        }
                        try {
                            Object value = convertBack(mGetter.invoke(target));
                            kf.setValue(value);
                            kf.setValueWasSetOnStart(true);
                        } catch (InvocationTargetException e) {
                            Log.e("PropertyValuesHolder", e.toString());
                        } catch (IllegalAccessException e) {
                            Log.e("PropertyValuesHolder", e.toString());
                        }
                    }
                }
            }
        }
    
    其中: if (mSetter == null) {setupSetter(targetClass);}
    private void setupGetter(Class targetClass) {
            mGetter = setupSetterOrGetter(targetClass, sGetterPropertyMap, "get", null);
        }
    //继续深入
    private Method setupSetterOrGetter(Class targetClass,
                HashMap<Class, HashMap<String, Method>> propertyMapMap,
                String prefix, Class valueType) {
            Method setterOrGetter = null;
            synchronized(propertyMapMap) {
                // Have to lock property map prior to reading it, to guard against
                // another thread putting something in there after we've checked it
                // but before we've added an entry to it
                HashMap<String, Method> propertyMap = propertyMapMap.get(targetClass);
                boolean wasInMap = false;
                if (propertyMap != null) {
                    wasInMap = propertyMap.containsKey(mPropertyName);
                    if (wasInMap) {
                        setterOrGetter = propertyMap.get(mPropertyName);
                    }
                }
                if (!wasInMap) {
                    setterOrGetter = getPropertyFunction(targetClass, prefix, valueType);
                    if (propertyMap == null) {
                        propertyMap = new HashMap<String, Method>();
                        propertyMapMap.put(targetClass, propertyMap);
                    }
                    propertyMap.put(mPropertyName, setterOrGetter);
                }
            }
            return setterOrGetter;
        }
    
    //其中: setterOrGetter = getPropertyFunction(targetClass, prefix, valueType);
     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 {
                args = new Class[1];
                Class typeVariants[];
                if (valueType.equals(Float.class)) {
                    typeVariants = FLOAT_VARIANTS;
                } else if (valueType.equals(Integer.class)) {
                    typeVariants = INTEGER_VARIANTS;
                } else if (valueType.equals(Double.class)) {
                    typeVariants = DOUBLE_VARIANTS;
                } else {
                    typeVariants = new Class[1];
                    typeVariants[0] = valueType;
                }
                for (Class typeVariant : typeVariants) {
                    args[0] = typeVariant;
                    try {
                        returnVal = targetClass.getMethod(methodName, args);
                        if (mConverter == null) {
                            // change the value type to suit
                            mValueType = typeVariant;
                        }
                        return returnVal;
                    } catch (NoSuchMethodException e) {
                        // Swallow the error and keep trying other variants
                    }
                }
                // If we got here, then no appropriate function was found
            }
    
            if (returnVal == null) {
                Log.w("PropertyValuesHolder", "Method " +
                        getMethodName(prefix, mPropertyName) + "() with type " + valueType +
                        " not found on target class " + targetClass);
            }
    
            return returnVal;
        }
    
    属性动画的原理就是不断调用view.setScrollX() view.setScrollY()
    

    相关文章

      网友评论

          本文标题:属性动画(ObjectAnimator)

          本文链接:https://www.haomeiwen.com/subject/vexfgttx.html