属性动画-Property Animation之ViewPropertyAnimator 你应该知道的一切

标签: 动画View属性动画PropertyAnimator
5381人阅读 评论(1) 收藏 举报
分类:

转载请注明出处(万分感谢!):
http://blog.csdn.net/javazejian/article/details/52381558
出自【zejian的博客】

关联文章:

走进绚烂多彩的属性动画-Property Animation(上篇)
走进绚烂多彩的属性动画-Property Animation之Interpolator和TypeEvaluator(下篇)
属性动画-Property Animation之ViewPropertyAnimator 你应该知道的一切
Android布局动画之animateLayoutChanges与LayoutTransition

  原本打算这篇作为属性动画的完结篇,但目前情况来看,估计无法完结,前两天研究了一下ViewPropertyAnimator这个android 3.1版本后新添加的类,感觉挺有必要用一篇文章来记录一下这个类,ViewPropertyAnimator本身也算不上什么高级类,自然也不是什么特殊技巧,那这个类到底是用来干什么的呢?这就是我们本篇的目的所在啦,接下来我们就来全面地了解一下ViewPropertyAnimator

1.ViewPropertyAnimator概述

  通过前两篇的学习,我们应该明白了属性动画的推出已不再是针对于View而进行设计的了,而是一种对数值不断操作的过程,我们可以将属性动画对数值的操作过程设置到指定对象的属性上来,从而形成一种动画的效果。虽然属性动画给我们提供了ValueAnimator类和ObjectAnimator类,在正常情况下,基本都能满足我们对动画操作的需求,但ValueAnimator类和ObjectAnimator类本身并不是针对View对象的而设计的,而我们在大多数情况下主要都还是对View进行动画操作的,因此Google官方在Android 3.1系统中补充了ViewPropertyAnimator类,这个类便是专门为View动画而设计的。当然这个类不仅仅是为提供View而简单设计的,它存在以下优点:

  • 专门针对View对象动画而操作的类。
  • 提供了更简洁的链式调用设置多个属性动画,这些动画可以同时进行的。
  • 拥有更好的性能,多个属性动画是一次同时变化,只执行一次UI刷新(也就是只调用一次invalidate,而n个ObjectAnimator就会进行n次属性变化,就有n次invalidate)。
  • 每个属性提供两种类型方法设置。
  • 该类只能通过View的animate()获取其实例对象的引用

  好~,下面我们来了解一下ViewPropertyAnimator常规使用

2.ViewPropertyAnimator常规使用

之前我们要设置一个View控件旋转360的代码是这样:

ObjectAnimator.ofFloat(btn,"rotation",360).setDuration(200).start();

而现在我们使用ViewPropertyAnimator后是这样:

btn.animate().rotation(360).setDuration(200);

  代码是不是特简洁?这里我们来解析一下,首先必须用View#animate()方法来获取一个ViewPropertyAnimator的对象实例,前面我们说过ViewPropertyAnimator支持链式操作,所以这里直接通过rotation方法设置旋转角度,再设置时间即可,有没有发现连动画的启动都不用我们去操作!是的,ViewPropertyAnimator内部会自动去调用
对于View#animate()方法,这里再说明一下,animate()方法是在Android 3.1系统上新增的一个方法,其作用就是返回ViewPropertyAnimator的实例对象,其源码如下,一目了然:

 /**
 * This method returns a ViewPropertyAnimator object, which can be used to animate
 * specific properties on this View.
 *
 * @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View.
 */
public ViewPropertyAnimator animate() {
    if (mAnimator == null) {
        mAnimator = new ViewPropertyAnimator(this);
    }
    return mAnimator;
}

接着我们再来试试别的方法,同时设置一组动画集合如下:

AnimatorSet set = new AnimatorSet();
set.playTogether( ObjectAnimator.ofFloat(btn,"alpha",0.5f),
        ObjectAnimator.ofFloat(btn,"rotation",360),
        ObjectAnimator.ofFloat(btn,"scaleX",1.5f),
        ObjectAnimator.ofFloat(btn,"scaleY",1.5f),
        ObjectAnimator.ofFloat(btn,"translationX",0,50),
        ObjectAnimator.ofFloat(btn,"translationY",0,50)
);
set.setDuration(5000).start();

使用ViewPropertyAnimator设置代码如下:

 btn.animate().alpha(0.5f).rotation(360).scaleX(1.5f).scaleY(1.5f)
              .translationX(50).translationY(50).setDuration(5000);

  是不是已经深深地爱上ViewPropertyAnimator?真的太简洁了!都快感动地哭出来了……先去厕所哭会…….好吧,ViewPropertyAnimator简单用法讲完了,这里小结一下ViewPropertyAnimator的常用方法:

Method Discription
alpha(float value) 设置透明度,value表示变化到多少,1不透明,0全透明。
scaleY(float value) 设置Y轴方向的缩放大小,value表示缩放到多少。1表示正常规格。小于1代表缩小,大于1代表放大。
scaleX(float value) 设置X轴方向的缩放大小,value表示缩放到多少。1表示正常规格。小于1代表缩小,大于1代表放大。
translationY(float value) 设置Y轴方向的移动值,作为增量来控制View对象相对于它父容器的左上角坐标偏移的位置,即移动到哪里。
translationX(float value) 设置X轴方向的移动值,作为增量来控制View对象相对于它父容器的左上角坐标偏移的位置。
rotation(float value) 控制View对象围绕支点进行旋转, rotation针对2D旋转
rotationX (float value) 控制View对象围绕X支点进行旋转, rotationX针对3D旋转
rotationY(float value) 控制View对象围绕Y支点进行旋转, rotationY针对3D旋转
x(float value) 控制View对象相对于它父容器的左上角坐标在X轴方向的最终位置。
y(float value) 控制View对象相对于它父容器的左上角坐标在Y轴方向的最终位置
void cancel() 取消当前正在执行的动画
setListener(Animator.AnimatorListener listener) 设置监听器,监听动画的开始,结束,取消,重复播放
setUpdateListener(ValueAnimator.AnimatorUpdateListener listener) 设置监听器,监听动画的每一帧的播放
setInterpolator(TimeInterpolator interpolator) 设置插值器
setStartDelay(long startDelay) 设置动画延长开始的时间
setDuration(long duration) 设置动画执行的时间
withLayer() 设置是否开启硬件加速
withStartAction(Runnable runnable) 设置用于动画监听开始(Animator.AnimatorListener)时运行的Runnable任务对象
withEndAction(Runnable runnable) 设置用于动画监听结束(Animator.AnimatorListener)时运行的Runnable任务对象

  以上便是ViewPropertyAnimator一些操作方法,其实上面很多属性设置方法都对应着一个By结尾的方法,其变量则代表的是变化量,如下:

我们看看其中scaleY与scaleYBy的实现:

public ViewPropertyAnimator scaleY(float value) {
        animateProperty(SCALE_Y, value);
        return this;
    }

public ViewPropertyAnimator scaleYBy(float value) {
    animatePropertyBy(SCALE_Y, value);
    return this;
}

再看看animateProperty()与 animatePropertyBy()

 private void animateProperty(int constantName, float toValue) {
        float fromValue = getValue(constantName);
        float deltaValue = toValue - fromValue;
        animatePropertyBy(constantName, fromValue, deltaValue);
    }

 private void animatePropertyBy(int constantName, float byValue) {
        float fromValue = getValue(constantName);
        animatePropertyBy(constantName, fromValue, byValue);
    }

  看了源码现在应该很清楚有By结尾(代表变化量的大小)和没By结尾(代表变化到多少)的方法的区别了吧。好~,再来看看监听器,实际上我们可以通过setListener(Animator.AnimatorListener listener)setUpdateListener(ValueAnimator.AnimatorUpdateListener listener)设置自定义监听器,而在ViewPropertyAnimator内部也有自己实现的监听器,同样我们可以看一下其实现源码:

private class AnimatorEventListener
            implements Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener {
        @Override
        public void onAnimationStart(Animator animation) {
            //调用了设置硬件加速的Runnable
            if (mAnimatorSetupMap != null) {
                Runnable r = mAnimatorSetupMap.get(animation);
                if (r != null) {
                    r.run();
                }
                mAnimatorSetupMap.remove(animation);
            }
            if (mAnimatorOnStartMap != null) {
                  //调用我们通过withStartAction(Runnable runnable)方法设置的runnable
                Runnable r = mAnimatorOnStartMap.get(animation);
                if (r != null) {
                    r.run();
                }
                mAnimatorOnStartMap.remove(animation);
            }
            if (mListener != null) {
                //调用我们自定义的监听器方法
                mListener.onAnimationStart(animation);
            }
        }



        @Override
        public void onAnimationCancel(Animator animation) {
            if (mListener != null) {
                //调用我们自定义的监听器方法
                mListener.onAnimationCancel(animation);
            }
            if (mAnimatorOnEndMap != null) {
                mAnimatorOnEndMap.remove(animation);
            }
        }

        @Override
        public void onAnimationRepeat(Animator animation) {
            if (mListener != null) {
                //调用我们自定义的监听器方法
                mListener.onAnimationRepeat(animation);
            }
        }

        @Override
        public void onAnimationEnd(Animator animation) {
            mView.setHasTransientState(false);
            if (mListener != null) {
                //调用我们自定义的监听器方法
                mListener.onAnimationEnd(animation);
            }
            if (mAnimatorOnEndMap != null) {
                  //调用我们通过withEndAction(Runnable runnable)方法设置的runnable
                Runnable r = mAnimatorOnEndMap.get(animation);
                if (r != null) {
                    r.run();
                }
                mAnimatorOnEndMap.remove(animation);
            }
            if (mAnimatorCleanupMap != null) {
               //移除硬件加速
                Runnable r = mAnimatorCleanupMap.get(animation);
                if (r != null) {
                    r.run();
                }
                mAnimatorCleanupMap.remove(animation);
            }
            mAnimatorMap.remove(animation);
        }

  由源码我们知道当监听器仅需要监听动画的开始和结束时,我们可以通过withStartAction(Runnable runnable)withEndAction(Runnable runnable)方法来设置一些特殊的监听操作。在AnimatorEventListener中的开始事件还会判断是否开启硬件加速,当然在动画结束时也会去关闭硬件加速。我们可以通过ViewPropertyAnimator #withLayer()方法开启硬件加速功能。到此对于ViewPropertyAnimator的常规使用方式已很清晰了。剩下的我们就来剖析剖析ViewPropertyAnimator内部到底是如何运作的,同时又是如何优化动画性能的。

3.ViewPropertyAnimator原理解析

  我们先通过一副图来大概了解一下ViewPropertyAnimator内部的整体运行工作原理(图太小的话请右键在新页面打开哈,不知为什么markdown限制了大小 。。郁闷中。。):

我们这里先给出整体执行流程(有个整体的概念就行哈,不理解也没有关系,看完下面的分析,再回来来看看也是可以),然后再详细分析:

  • 1.通过imageView.animate()获取ViewPropertyAnimator对象。
  • 2.调用alpha、translationX等方法,返回当前ViewPropertyAnimator对象,可以继续链式调用
  • 3.alpha、translationX等方法内部最终调用animatePropertyBy(int constantName, float startValue, float byValue)方法
  • 4.在animatePropertyBy方法中则会将alpha、translationX等方法的操作封装成NameVauleHolder,并将每个NameValueHolder对象添加到准备列表mPendingAnimations中。
  • 5.animatePropertyBy方法启动mAnimationStarter,调用startAnimation,开始动画。
  • 6.startAnimation方法中会创建一个ValueAnimator对象设置内部监听器AnimatorEventListener,并将mPendingAnimations和要进行动画的属性名称封装成一个PropertyBundle对象,最后mAnimatorMap保存当前Animator和对应的PropertyBundle对象。该Map将会在animatePropertyBy方法和Animator监听器mAnimatorEventListener中使用,启动动画。
  • 7.在动画的监听器的onAnimationUpdate方法中设置所有属性的变化值,并通过RenderNode类优化绘制性能,最后刷新界面。

  有了整体概念后,现在我们沿着该工作流程图的路线来分析ViewPropertyAnimator内部执行过程,从上图可以看出,通过View#animate()获取到ViewPropertyAnimator实例后,可以通过ViewPropertyAnimator提供的多种方法来设置动画,如translationX()、scaleX()等等,而当调用完这些方法后,其内部最终则会通过多次调用animatorPropertyBy(),我们先看看animatePropertyBy方法源码:

/**
     * Utility function, called by animateProperty() and animatePropertyBy(), which handles the
     * details of adding a pending animation and posting the request to start the animation.
     *
     * @param constantName The specifier for the property being animated
     * @param startValue The starting value of the property
     * @param byValue The amount by which the property will change
     */
    private void animatePropertyBy(int constantName, float startValue, float byValue) {
        // First, cancel any existing animations on this property
        //判断该属性上是否存在运行的动画,存在则结束。
        if (mAnimatorMap.size() > 0) {
            Animator animatorToCancel = null;
            Set<Animator> animatorSet = mAnimatorMap.keySet();
            for (Animator runningAnim : animatorSet) {
                PropertyBundle bundle = mAnimatorMap.get(runningAnim);
                if (bundle.cancel(constantName)) {// 结束对应属性动画
                    // property was canceled - cancel the animation if it's now empty
                    // Note that it's safe to break out here because every new animation
                    // on a property will cancel a previous animation on that property, so
                    // there can only ever be one such animation running.
                    if (bundle.mPropertyMask == NONE) {//判断是否还有其他属性
                        // the animation is no longer changing anything - cancel it
                        animatorToCancel = runningAnim;
                        break;
                    }
                }
            }
            if (animatorToCancel != null) {
                animatorToCancel.cancel();
            }
        }
//将要执行的属性的名称,开始值,变化值封装成NameValuesHolder对象
        NameValuesHolder nameValuePair = new NameValuesHolder(constantName, startValue, byValue);
        //添加到准备列表中
        mPendingAnimations.add(nameValuePair);
        mView.removeCallbacks(mAnimationStarter);
        mView.postOnAnimation(mAnimationStarter);
    }

  从源码可以看出,animatePropertyBy方法主要干了以下几件事:

  • 首先会去当前属性是否还有在动画在执行,如果有则先结束该属性上的动画,保证该属性上只有一个Animator在进行动画操作。
  • 将本次动画需要执行的动画属性封装成一个NameValueHolder对象
  • 将每个NameValuesHolder对象添加到mPendingAnimations的准备列表中

  NameValuesHolder对象是一个内部类,其相关信息如下:
NameValueHolder:内部类,封装每个要进行动画属性值开始值和变化值,比如translationX(200),那么这个动画的属性值、开始值和变化值将被封装成一个NameValueHolder,其源码也非常简单:

static class NameValuesHolder {
        int mNameConstant;//要进行动画的属性名称
        float mFromValue;//开始值
        float mDeltaValue;//变化值
        NameValuesHolder(int nameConstant, float fromValue, float deltaValue) {
            mNameConstant = nameConstant;
            mFromValue = fromValue;
            mDeltaValue = deltaValue;
        }
    }

  而mPendingAnimations的相关信息如下:
mPendingAnimations:装载的是准备进行动画的属性值(NameValueHolder)所有列表,也就是每次要同时进行动画的全部属性的集合

ArrayList<NameValuesHolder> mPendingAnimations = new ArrayList<NameValuesHolder>();

  当添加完每个要运行的属性动画后,则会通过mAnimationStarter对象去调用startAnimation(),启动动画。
Runnable mAnimationStarter: 用来执行动画的Runnable。它会执行startAnimation方法,而在startAnimation方法中会通过animator.start()启动动画,源码非常简洁:

private Runnable mAnimationStarter = new Runnable() {
        @Override
        public void run() {
            startAnimation();
        }
};

接着我们看看startAnimation()的源码:

/**
 * Starts the underlying Animator for a set of properties. We use a single animator that
 * simply runs from 0 to 1, and then use that fractional value to set each property
 * value accordingly.
 */
private void startAnimation() {
    if (mRTBackend != null && mRTBackend.startAnimation(this)) {
        return;
    }
    mView.setHasTransientState(true);
    //创建ValueAnimator
    ValueAnimator animator = ValueAnimator.ofFloat(1.0f);
    //clone一份mPendingAnimations赋值给nameValueList
    ArrayList<NameValuesHolder> nameValueList =
            (ArrayList<NameValuesHolder>) mPendingAnimations.clone();
     //赋值完后清空
    mPendingAnimations.clear();
    //用于标识要执行动画的属性
    int propertyMask = 0;
    int propertyCount = nameValueList.size();
    //遍历所有nameValuesHolder,取出其属性名称mNameConstant,
    //执行"|"操作并最终赋值propertyMask
    for (int i = 0; i < propertyCount; ++i) {
        NameValuesHolder nameValuesHolder = nameValueList.get(i);
        propertyMask |= nameValuesHolder.mNameConstant;
    }
    //创建PropertyBundle,并添加到mAnimatorMap中
    mAnimatorMap.put(animator, new PropertyBundle(propertyMask, nameValueList));
    if (mPendingSetupAction != null) {
        //设置硬件加速
        mAnimatorSetupMap.put(animator, mPendingSetupAction);
        mPendingSetupAction = null;
    }
    if (mPendingCleanupAction != null) {
       //移除硬件加速
        mAnimatorCleanupMap.put(animator, mPendingCleanupAction);
        mPendingCleanupAction = null;
    }
    if (mPendingOnStartAction != null) {
        //设置开始的动画(监听器的开始方法中调用)
        mAnimatorOnStartMap.put(animator, mPendingOnStartAction);
        mPendingOnStartAction = null;
    }
    if (mPendingOnEndAction != null) {
        //设置结束后要进行的下一个动画(监听器的结束方法中调用)
        mAnimatorOnEndMap.put(animator, mPendingOnEndAction);
        mPendingOnEndAction = null;
    }
    //添加内部监听器
    animator.addUpdateListener(mAnimatorEventListener);
    animator.addListener(mAnimatorEventListener);
    //判断是否延长开始
    if (mStartDelaySet) {
        animator.setStartDelay(mStartDelay);
    }
    //执行动画的实现
    if (mDurationSet) {
        animator.setDuration(mDuration);
    }
    //设置插值器
    if (mInterpolatorSet) {
        animator.setInterpolator(mInterpolator);
    }
    //开始执行动画
    animator.start();
}

  我们上面的注释非常全面,这里startAnimation主要做下面几件事:

  • 创建Animator,变化值从0到1,设置内部监听器mAnimatorEventListener。
  • clone一份mPendingAnimations列表,并计算属性值标记propertyMask,封装成PropertyBundle对象。
  • 使用mAnimatorMap保存当前Animator和对应的PropertyBundle对象。该Map将会在animatePropertyBy方法和Animator监听器mAnimatorEventListener中使用。
  • 启动animator动画。


  关于PropertyBundle的分析如下:
PropertyBundle: 内部类,存放着将要执行的动画的属性集合信息,每次调用animator.start();前,都会将存放在mPendingAnimations的clone一份存入PropertyBundle的内部变量mNameValuesHolder中,然后再将遍历mPendingAnimations中的NameValueHolder类,取出要执行的属性进行”|”操作,最后记录成一个mPropertyMask的变量,存放在PropertyBundle中,PropertyBundle就是最终要执行动画的全部属性的封装类,其内部结构如下图

AnimatorEventListener: ViewPropertyAnimator内部的监听器。这个类实现了Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener接口。我们前面已经分享过它的部分源码,这个类还有一个onAnimationUpdate()的监听方法,这个方法我们放在后面解析,它是动画执行的关键所在。

HashMap mAnimatorMap: 存放PropertyBundle类的Map。这个Map中存放的是正在执行的动画的PropertyBundle,这个PropertyBundle包含这本次动画的所有属性的信息。最终在AnimatorEventListener的onAnimationUpdate()方法中会通过这个map获取相应的属性,然后不断更新每帧的属性值以达到动画效果。通过前面对animatePropertyBy方法的分析,我们可以知道该Map会保证当前只有一个Animator对象对该View的属性进行操作,不会存在两个Animator在操作同一个属性,其声明如下:

private HashMap<Animator, PropertyBundle> mAnimatorMap =

        new HashMap<Animator, PropertyBundle>();

  最后我们看看动画是在哪里执行的,根据我们前面的原理图,内部监听器的onAnimationUpdate()方法将会被调用(当然内部监听器AnimatorEventListener实现了两个动画监听接口,其开始,结束,重复,取消4个方法也会被调用,这个我们前面已分析过)。

@Override
        public void onAnimationUpdate(ValueAnimator animation) {
        //取出当前Animator对应用propertyBundle对象
            PropertyBundle propertyBundle = mAnimatorMap.get(animation);
            if (propertyBundle == null) {
                // Shouldn't happen, but just to play it safe
                return;
            }
        //是否开启了硬件加速
            boolean hardwareAccelerated = mView.isHardwareAccelerated();

            // alpha requires slightly different treatment than the other (transform) properties.
            // The logic in setAlpha() is not simply setting mAlpha, plus the invalidation
            // logic is dependent on how the view handles an internal call to onSetAlpha().
            // We track what kinds of properties are set, and how alpha is handled when it is
            // set, and perform the invalidation steps appropriately.
            boolean alphaHandled = false;
            if (!hardwareAccelerated) {
                mView.invalidateParentCaches();
            }
            //取出当前的估算值(插值器计算值)
            float fraction = animation.getAnimatedFraction();
            int propertyMask = propertyBundle.mPropertyMask;
            if ((propertyMask & TRANSFORM_MASK) != 0) {
                mView.invalidateViewProperty(hardwareAccelerated, false);
            }
            //取出所有要执行的属性动画的封装对象NameValuesHolder
            ArrayList<NameValuesHolder> valueList = propertyBundle.mNameValuesHolder;
            if (valueList != null) {
                int count = valueList.size();
                //遍历所有NameValuesHolder,计算变化值,并设置给对应的属性
                for (int i = 0; i < count; ++i) {
                    NameValuesHolder values = valueList.get(i);
                    float value = values.mFromValue + fraction * values.mDeltaValue;
                    if (values.mNameConstant == ALPHA) {
                        alphaHandled = mView.setAlphaNoInvalidation(value);
                    } else {
                        setValue(values.mNameConstant, value);
                    }
                }
            }
            if ((propertyMask & TRANSFORM_MASK) != 0) {
                if (!hardwareAccelerated) {
                    mView.mPrivateFlags |= View.PFLAG_DRAWN; // force another invalidation
                }
            }
            // invalidate(false) in all cases except if alphaHandled gets set to true
            // via the call to setAlphaNoInvalidation(), above
            if (alphaHandled) {
                mView.invalidate(true);
            } else {
                mView.invalidateViewProperty(false, false);
            }
            if (mUpdateListener != null) {
                mUpdateListener.onAnimationUpdate(animation);
            }
        }

  onAnimationUpdate方法主要做了以下几件事:

  • 取出当前Animator对应用propertyBundle对象并获取当前的估算值(插值器计算值),用于后续动画属性值的计算
  • 从propertyBundle取出要进行动画的属性列表 ArrayList<NameValuesHolder> valueList
  • 遍历所有NameValuesHolder,计算变化值,并通过setValue设置给对应的属性,如果是ALPHA,则会特殊处理一下,最终形成动画效果

setValue方法源码:

 private void setValue(int propertyConstant, float value) {
        final View.TransformationInfo info = mView.mTransformationInfo;
        final RenderNode renderNode = mView.mRenderNode;
        switch (propertyConstant) {
            case TRANSLATION_X:
                renderNode.setTranslationX(value);
                break;
            case TRANSLATION_Y:
                renderNode.setTranslationY(value);
                break;
            case TRANSLATION_Z:
                renderNode.setTranslationZ(value);
                break;
            case ROTATION:
                renderNode.setRotation(value);
                break;
            case ROTATION_X:
                renderNode.setRotationX(value);
                break;
            case ROTATION_Y:
                renderNode.setRotationY(value);
                break;
            case SCALE_X:
                renderNode.setScaleX(value);
                break;
            case SCALE_Y:
                renderNode.setScaleY(value);
                break;
            case X:
                renderNode.setTranslationX(value - mView.mLeft);
                break;
            case Y:
                renderNode.setTranslationY(value - mView.mTop);
                break;
            case Z:
                renderNode.setTranslationZ(value - renderNode.getElevation());
                break;
            case ALPHA:
                info.mAlpha = value;
                renderNode.setAlpha(value);
                break;
        }
    }

  从源码可以看出实际上都会把属性值的改变设置到renderNode对象中,而RenderNode类则是一个可以优化绘制流程和绘制动画的类,该类可以提升优化绘制的性能,其内部操作最终会去调用到Native层方法,这里我们就不深追了。
  最后这里我们再回忆一下前面给出的整体流程说明:

  • 1.通过imageView.animate()获取ViewPropertyAnimator对象。
  • 2.调用alpha、translationX等方法,返回当前ViewPropertyAnimator对象,可以继续链式调用
  • 3.alpha、translationX等方法内部最终调用animatePropertyBy(int constantName, float startValue, float byValue)方法
  • 4.在animatePropertyBy方法中则会将alpha、translationX等方法的操作封装成NameVauleHolder,并将每个NameValueHolder对象添加到准备列表mPendingAnimations中。
  • 5.animatePropertyBy方法启动mAnimationStarter,调用startAnimation,开始动画。
  • 6.startAnimation方法中会创建一个ValueAnimator对象设置内部监听器AnimatorEventListener,并将mPendingAnimations和要进行动画的属性名称封装成一个PropertyBundle对象,最后mAnimatorMap保存当前Animator和对应的PropertyBundle对象。该Map将会在animatePropertyBy方法和Animator监听器mAnimatorEventListener中使用,启动动画。
  • 7.在动画的监听器的onAnimationUpdate方法中设置所有属性的变化值,并通过RenderNode类优化绘制性能,最后刷新界面。

  现在应该比较清晰了吧,以上就是ViewPropertyAnimator内部的大概执行流程。好~,ViewPropertyAnimator介绍到这。

关联文章:
走进绚烂多彩的属性动画-Property Animation(上篇)
走进绚烂多彩的属性动画-Property Animation之Interpolator和TypeEvaluator(下篇)
属性动画-Property Animation之ViewPropertyAnimator 你应该知道的一切

3
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:628478次
    • 积分:5828
    • 等级:
    • 排名:第4983名
    • 原创:64篇
    • 转载:0篇
    • 译文:0篇
    • 评论:442条
    联系我
    邮箱:shinezejian@163.com
    最新评论