ViewPropertyAnimator源码分析

ViewPropertyAnimator的源码解析

最近对android中的动画特别感兴趣,可能是因为比较喜欢跟UI相关的东西吧。这篇文章将简单的介绍下ViewPropertyAnimator这个类的源码和一些使用。本文中的例子来自郭神的博客,在文章的最后会奉上三篇郭神的博客,关于属性动画的。非常感谢郭神的博客和书,在android的路上指引我们前进,特此感谢。

简述

ViewPropertyAnimator这个类出现的原因应该是android为了方便我们在使用对于View对象的属性动画的时候而封装的一个类,让我们能够更好的,更简单的使用属性动画。在看文章之前,需要对属性动画有一定的了解,才能更好的弄明白这个类的作用的方便之处。还是推荐看郭神的博客。

我们都知道,在android中动画可以分为这几种,补间动画,帧动画,属性动画,当然了,现在可能还有的就是SVG矢量动画,之后可能会写关于矢量动画的博客。先说前三种,优缺点什么的,怎么用什么的。请自行百度。百度之后可以去看郭神的博客,有三篇关于属性动画的高级使用。这篇文章就是接着郭神没说完的ViewPropertyAnimator来进行讲解的。推荐大家以后做属性动画的时候都采用这种方式,真的是好用。

源码

本人英文不是很好,对于android的理解也一般,如果有不对的地方,请不吝赐教。

先说下构造方法,因为这个类是专门用来处理View的属性动画的,所以它对象的创建必须跟View有关。

/**
 * 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;
}`

我们可以通过view.animate()方法来获得一个ViewPropertyAnimator对象,之后就可以使用ViewPropertyAnimator中的方法来实现我们想要的动画。注意ViewPropertyAnimator中的方法返回值都是ViewPropertyAnimator对象,也就是说我们可以通过连缀的方式来实现对动画的设置。
接下来让我们来看下ViewPropertyAnimator这个类里面都有什么,先看属性。

`
//关联的view对象
private final View mView;
 //动画时长
private long mDuration;
//是否设置动画时长
private boolean mDurationSet = false;
//动画开始延迟
private long mStartDelay = 0;
//是否设置动画开始延迟
private boolean mStartDelaySet = false;
    //差值器
private TimeInterpolator mInterpolator;
    //是否设置差值器
private boolean mInterpolatorSet = false;
    //动画监听器
private Animator.AnimatorListener mListener = null;
//动画监听器(私有内部类,之后会讲到)
private AnimatorEventListener mAnimatorEventListener = new AnimatorEventListener();
//NameValuesHolder的集合
ArrayList<NameValuesHolder> mPendingAnimations = new ArrayList<NameValuesHolder>();
//不同动作所执行的不同的任务类
private Runnable mPendingSetupAction;
private Runnable mPendingCleanupAction;
private Runnable mPendingOnStartAction;
private Runnable mPendingOnEndAction;
    //View的常见属性  
private static final int NONE           = 0x0000;
private static final int TRANSLATION_X  = 0x0001;
private static final int TRANSLATION_Y  = 0x0002;
private static final int SCALE_X        = 0x0004;
private static final int SCALE_Y        = 0x0008;
private static final int ROTATION       = 0x0010;
private static final int ROTATION_X     = 0x0020;
private static final int ROTATION_Y     = 0x0040;
private static final int X              = 0x0080;
private static final int Y              = 0x0100;
private static final int ALPHA          = 0x0200;

private static final int TRANSFORM_MASK = TRANSLATION_X | TRANSLATION_Y | SCALE_X | SCALE_Y |
        ROTATION | ROTATION_X | ROTATION_Y | X | Y;

//开启动画的任务
private Runnable mAnimationStarter = new Runnable() {
    @Override
    public void run() {
        startAnimation();
    }
};

/**
 * This class holds information about the overall animation being run on the set of
 * properties. The mask describes which properties are being animated and the
 * values holder is the list of all property/value objects.
     *这个类包含关于在集合中运行的全局动画的信息。该掩码描述了正在动画中的属性和值保持器是所有属性/值对象的列表。
     *百度翻译。。。。。 
 */   
private static class PropertyBundle {
    int mPropertyMask;
    ArrayList<NameValuesHolder> mNameValuesHolder;

    PropertyBundle(int propertyMask, ArrayList<NameValuesHolder> nameValuesHolder) {
        mPropertyMask = propertyMask;
        mNameValuesHolder = nameValuesHolder;
    }
        //是否成功取消动画
    boolean cancel(int propertyConstant) {
        if ((mPropertyMask & propertyConstant) != 0 && mNameValuesHolder != null) {
            int count = mNameValuesHolder.size();
            for (int i = 0; i < count; ++i) {
                NameValuesHolder nameValuesHolder = mNameValuesHolder.get(i);
                if (nameValuesHolder.mNameConstant == propertyConstant) {
                    mNameValuesHolder.remove(i);
                    mPropertyMask &= ~propertyConstant;
                    return true;
                }
            }
        }
        return false;
    }
}

/**
 * This list tracks the list of properties being animated by any particular animator.
 * In most situations, there would only ever be one animator running at a time. But it is
 * possible to request some properties to animate together, then while those properties
 * are animating, to request some other properties to animate together. The way that
 * works is by having this map associate the group of properties being animated with the
 * animator handling the animation. On every update event for an Animator, we ask the
 * map for the associated properties and set them accordingly.
 */
 //这个大家自行翻译吧,我怕我翻译不好说错了影响大家,表面上就是五个Map分别保存着PropertyBundle
 //和不同的任务对象
private HashMap<Animator, PropertyBundle> mAnimatorMap =
        new HashMap<Animator, PropertyBundle>();
private HashMap<Animator, Runnable> mAnimatorSetupMap;
private HashMap<Animator, Runnable> mAnimatorCleanupMap;
private HashMap<Animator, Runnable> mAnimatorOnStartMap;
private HashMap<Animator, Runnable> mAnimatorOnEndMap;

//这个类持有着我们想要更改的属性和对应的值。可以这么理解为比如alpha 0f,1f
private static class NameValuesHolder {
    int mNameConstant;
    float mFromValue;
    float mDeltaValue;
    NameValuesHolder(int nameConstant, float fromValue, float deltaValue) {
        mNameConstant = nameConstant;
        mFromValue = fromValue;
        mDeltaValue = deltaValue;
    }
}

/**
 * Constructor, called by View. This is private by design, as the user should only
 * get a ViewPropertyAnimator by calling View.animate().
 *构造方法,被View调用,设计成私有的是为了使用者只能通过View.animate()方法调用来获得一个ViewPropertyAnimator对象
 * @param view The View associated with this ViewPropertyAnimator
 */
ViewPropertyAnimator(View view) {
    mView = view;
    view.ensureTransformationInfo();
}

`
好了,通过上面的代码。我们对ViewPropertyAnimator这个类有了一个初步的认识,基本的属性都有一个简单的认识(哎,英文不好见谅),接下来我们来看看它都有哪些方法。

大家可以看到在图片中有很多对View属性进行设置的方法,而且方法的返回值都是ViewpropertyAnimator对象,这样我能就可以使用连缀了。找其中一个看看。

 public ViewPropertyAnimator alpha(float value) {
    animateProperty(ALPHA, value);
    return this;
}

可以看到其中执行了animateProperty这个方法,跟踪过去看看。

/**
 * 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 nameValuePair = new NameValuesHolder(constantName, startValue, byValue);
    mPendingAnimations.add(nameValuePair);
    mView.removeCallbacks(mAnimationStarter);
    mView.post(mAnimationStarter);
}`

其中开始的部分是把之前在运行的动画取消掉,然后把需要对view那个属性进行修改和要修改的值封装到nameValuePair中,添加到mPendingAnimations,最后调用View的Post方法在主线程中执行。而动画的开始是在mAnimationStarter这个任务对象中的,可以看下之前的代码就会发现其中调用了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() {
    mView.setHasTransientState(true);
    ValueAnimator animator = ValueAnimator.ofFloat(1.0f);
    ArrayList<NameValuesHolder> nameValueList =
            (ArrayList<NameValuesHolder>) mPendingAnimations.clone();
    mPendingAnimations.clear();
    int propertyMask = 0;
    int propertyCount = nameValueList.size();
    for (int i = 0; i < propertyCount; ++i) {
        NameValuesHolder nameValuesHolder = nameValueList.get(i);
        propertyMask |= nameValuesHolder.mNameConstant;
    }
    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();
}`

可以看到其中对之前的属性进行了判断,如果不为null的话就添加到Map中进行统一的管理,最后加上监听,设置常用属性,这样这个动画就开始了。当然了,一个ViewPropertyAnimator肯定不止于此它还有许多能够丰富动画效果的方法比如withLayer,withStartAction,withEndAction等,不过我们日常需求所要用的方法上面你都有介绍了,而且这个动画会自己启动不需要我能去调用Start()方法来启动动画,当然也可以显示的调用来执行,也支持去掉,同样支持动画的实时监听。

textview.animate().x(500).y(500).setDuration(5000)  
        .setInterpolator(new BounceInterpolator()); 

常用的调用方式,直接点就可以,不需要更多的操作。

总结

ViewPropertyAnimator这个类多与我们平时写属性的动画真的帮助很大,而且更加方便使用,易于理解,,代码看起来也更加的美观。但它只是针对于view的,不是之前使用的valueAnimator那样可以针对所有的对象,所以如果在之后的工作中如果想要更改View的属性的话推荐用它,如果是其他的不是view的就需要使用ValueAnimator来实现控制。总体来说还是很好用的 ^_^.

参看资料

关于属性动画,也许你只需要弄明白三篇博客就可以随心所欲了。
http://blog.csdn.net/guolin_blog/article/details/43536355
http://blog.csdn.net/guolin_blog/article/details/43816093
http://blog.csdn.net/guolin_blog/article/details/44171115

感觉高级属性动画还有一个东西至关重要,那就是会写差值器。好了这篇博客就到这里了,有不对的地方欢迎指出。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值