前言
平常所做的动画大部分是针对View的,而View经常会需要集中动画混合在一起做,因此提供了一个ViewPropertyAnimator类来快速的实现多个动画的混合;
ViewPropertyAnimator从名字就可以看出是专用于View的属性动画,在API12被提供;
ViewPropertyAnimator专用于操作View动画,语法更加简洁,使用更加方便;
今天就来看看怎么用;
一、ViewPropertyAnimator使用详解
1、获取对象
ViewPropertyAnimator 没有构造函数,通过View.animate()方法可以方便的获取;ViewPropertyAnimator 对象,此时获取的动画对象就专用于操作当前view;
- public ViewPropertyAnimator animate() {
- if (mAnimator == null) {
- mAnimator = new ViewPropertyAnimator(this);
- }
- return mAnimator;
- }
2、基本函数属性介绍
- alpha(float value) 设置View的透明度,value最终值;
- alphaBy(float value) 设置View的透明度,value是在view当前值的基础上的偏移量;rotation(float value):旋转View,正值顺时针,负值逆时针,value最终值;
- rotationBy(float value):旋转,在当前值得基础上偏移量;
- rotationX(float value):绕x轴旋转;
- rotationXBy(float value):当View旋转的基础上以value为偏移量绕X轴旋转;
- rotationY(float value):绕Y轴旋转;
- rotationYBy(float value):在当前旋转的基础上绕Y轴旋转;
- scaleX(float value):缩放view的X轴方向上的大小;
- scaleXBy(float value):当前View缩放的基础上,在X轴方向上对view进行缩放;
- scaleY(float value):缩放view的Y轴方向上的大小;
- scaleYBy(float value):当前View缩放的基础上,对view的Y轴方向进行缩放;
- translationX(float value):沿X轴方向平移,value大于0,X轴正方向;
- translationXBy(float value):带有偏移量的平移;
- translationY(float value):沿Y轴方向平移,value大于0,沿Y轴正方向平移;
- translationYBy(float value) :在当前值的基础上,在Y轴方向上平移;
- x(float value):在当前值的基础上,修改view 的X坐标;
- xBy(float value):在当前值的基础上,修改view 的X坐标;
- y(float value):在当前值的基础上,修改View的Y的坐标;
- yBy(float value):在当前值的基础上,修改View的Y的坐标;
- z(float value):在当前值的基础上,修改View的Z的坐标;
- zBy(float value):在当前值的基础上,修改View的Z的坐标;
3、基本使用
常用方法
- btnShow.animate()
- .setDuration(5000)
- //透明度
- .alpha(0)
- .alphaBy(0)
- //旋转
- .rotation(360)
- .rotationBy(360)
- .rotationX(360)
- .rotationXBy(360)
- .rotationY(360)
- .rotationYBy(360)
- //缩放
- .scaleX(1)
- .scaleXBy(1)
- .scaleY(1)
- .scaleYBy(1)
- //平移
- .translationX(100)
- .translationXBy(100)
- .translationY(100)
- .translationYBy(100)
- .translationZ(100)
- .translationZBy(100)
- //更改在屏幕上的坐标
- .x(10)
- .xBy(10)
- .y(10)
- .yBy(10)
- .z(10)
- .zBy(10)
- //监听及其他设置
- .setInterpolator(new BounceInterpolator())
- .setStartDelay(1000)
- .setListener(new Animator.AnimatorListener() {
- @Override
- public void onAnimationStart(Animator animation) {
- }
- @Override
- public void onAnimationEnd(Animator animation) {
- }
- @Override
- public void onAnimationCancel(Animator animation) {
- }
- @Override
- public void onAnimationRepeat(Animator animation) {
- }
- })
- .setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- }
- })
- .withEndAction(new Runnable() {
- @Override
- public void run() {
- Log.i(TAG, "run: end");
- }
- })
- .withStartAction(new Runnable() {
- @Override
- public void run() {
- Log.i(TAG, "run: start");
- }
- })
- .start();
4、添加监听
- setUpdateListener:添加动画属性变化监听
- setListener:添加动画状态监听
- ViewPropertyAnimator viewPropertyAnimator = gongxiang.animate().setDuration(3000).x(700).y(700).rotation(270).alpha(0.5f).setUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- );
- }
- }).setListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationCancel(Animator animation) {
- super.onAnimationCancel(animation);
- }
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- System.out.println("=========onAnimationEnd=======");
- }
- @Override
- public void onAnimationRepeat(Animator animation) {
- super.onAnimationRepeat(animation);
- }
- @Override
- public void onAnimationStart(Animator animation) {
- super.onAnimationStart(animation);
- System.out.println("=========onAnimationStart=======");
- }
- @Override
- public void onAnimationPause(Animator animation) {
- super.onAnimationPause(animation);
- }
- @Override
- public void onAnimationResume(Animator animation) {
- super.onAnimationResume(animation);
- }
- });
二、基本原理
1、执行动画基本步骤如下
- 通过test.animate()获取ViewPropertyAnimator对象;
- 调用alpha、translationX等方法,返回当前ViewPropertyAnimator对象,可以继续链式调用;
- alpha、translationX等方法内部最终调用animatePropertyBy(int constantName, float startValue, float byValue)方法;
- 在animatePropertyBy方法中则会将alpha、translationX等方法的操作封装成NameVauleHolder,并将每个NameValueHolder对象添加到准备列表mPendingAnimations中;
- animatePropertyBy方法启动mAnimationStarter,调用startAnimation,开始动画;
- startAnimation方法中会创建一个ValueAnimator对象设置内部监听器;AnimatorEventListener,并将mPendingAnimations和要进行动画的属性名称封装成一个PropertyBundle对象,最后mAnimatorMap保存当前Animator和对应的PropertyBundle对象,该Map将会在animatePropertyBy方法和Animator监听器mAnimatorEventListener中使用,启动动画;
- 在动画的监听器的onAnimationUpdate方法中设置所有属性的变化值,并通过RenderNode类优化绘制性能,最后刷新界面;
2、startAnimation()的源码
-
- private void startAnimation() {
- if (mRTBackend != null && mRTBackend.startAnimation(this)) {
- return;
- }
- mView.setHasTransientState(true);
- //创建ValueAnimator
- ValueAnimator animator = ValueAnimator.ofFloat(1.0f);
- //clone一份mPendingAnimations赋值给nameValueList
- ArrayList
nameValueList = - (ArrayList
) 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();
- }
- 创建Animator,变化值从0到1,设置内部监听器mAnimatorEventListener;
- clone一份mPendingAnimations列表,并计算属性值标记propertyMask,封装成PropertyBundle对象;
- 使用mAnimatorMap保存当前Animator和对应的PropertyBundle对象;
- 该Map将会在animatePropertyBy方法和Animator监听器mAnimatorEventListener中使用;
- 启动animator动画;
2、PropertyBundle
- private static class PropertyBundle {
- int mPropertyMask;
- ArrayList
mNameValuesHolder; - PropertyBundle(int propertyMask, ArrayList
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;
- }
- }
PropertyBundle:内部类,存放着将要执行的动画的属性集合信息,每次调用animator.start();
都会将存放在mPendingAnimations的clone一份存入PropertyBundle的内部变量mNameValuesHolder中,然后再将遍历mPendingAnimations中的NameValueHolder类,取出要执行的属性进行”|”操作;
最后记录成一个mPropertyMask的变量,存放在PropertyBundle中,PropertyBundle就是最终要执行动画的全部属性的封装类;
3、AnimatorEventListener
- private class AnimatorEventListener
- implements Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener {
- ...
- ...
- }
ViewPropertyAnimator内部的监听器:这个类实现了Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener接口;
这个类还有一个onAnimationUpdate()的监听方法,它是动画执行的关键所在;
4、mAnimatorMap
- private HashMap
mAnimatorMap = - new HashMap
();
- mAnimatorMap:存放PropertyBundle类的Map,这个Map中存放的是正在执行的动画的PropertyBundle,这个PropertyBundle包含这本次动画的所有属性的信息;
- 最终在AnimatorEventListener的onAnimationUpdate()方法中会通过这个map获取相应的属性,然后不断更新每帧的属性值以达到动画效果;
- 通过前面对animatePropertyBy方法的分析,我们可以知道该Map会保证当前只有一个Animator对象对该View的属性进行操作,不会存在两个Animator在操作同一个属性;
5、onAnimationUpdate
- @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
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);
- }
- }
取出当前Animator对应用propertyBundle对象并获取当前的估算值(插值器计算值),用于后续动画属性值的计算;
从propertyBundle取出要进行动画的属性列表 ArrayList
遍历所有NameValuesHolder,计算变化值,并通过setValue设置给对应的属性,如果是ALPHA,则会特殊处理一下,最终形成动画效果;
总结
年底了,有疫情有裁员,大家要努力,一起加油