动画 ViewPropertyAnimator 使用详解和原理分析
本文转载自微信公众号「Android开发编程」,动画作者Android开发编程。使用转载本文请联系Android开发编程公众号。详解析
前言
平常所做的和原动画大部分是针对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):在当前值的基础上,云南idc服务商修改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()的站群服务器源码
/** * 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(); } 创建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<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; } }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<Animator, PropertyBundle> mAnimatorMap = new HashMap<Animator, PropertyBundle>(); 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) { // Shouldnt 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); } }取出当前Animator对应用propertyBundle对象并获取当前的估算值(插值器计算值),用于后续动画属性值的计算;
从propertyBundle取出要进行动画的属性列表 ArrayList valueList;
遍历所有NameValuesHolder,计算变化值,并通过setValue设置给对应的属性,如果是ALPHA,则会特殊处理一下,最终形成动画效果;
总结
年底了,有疫情有裁员,大家要努力,一起加油