文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

动画 ViewPropertyAnimator 使用详解和原理分析

2024-12-02 13:18

关注

前言

平常所做的动画大部分是针对View的,而View经常会需要集中动画混合在一起做,因此提供了一个ViewPropertyAnimator类来快速的实现多个动画的混合;

ViewPropertyAnimator从名字就可以看出是专用于View的属性动画,在API12被提供;

ViewPropertyAnimator专用于操作View动画,语法更加简洁,使用更加方便;

今天就来看看怎么用;

一、ViewPropertyAnimator使用详解

1、获取对象

ViewPropertyAnimator 没有构造函数,通过View.animate()方法可以方便的获取;ViewPropertyAnimator 对象,此时获取的动画对象就专用于操作当前view;

  1. public ViewPropertyAnimator animate() { 
  2.     if (mAnimator == null) { 
  3.         mAnimator = new ViewPropertyAnimator(this); 
  4.     } 
  5.     return mAnimator; 

2、基本函数属性介绍

3、基本使用

常用方法

  1. btnShow.animate() 
  2.                         .setDuration(5000) 
  3.                         //透明度 
  4.                         .alpha(0) 
  5.                         .alphaBy(0) 
  6.                         //旋转 
  7.                         .rotation(360) 
  8.                         .rotationBy(360) 
  9.                         .rotationX(360) 
  10.                         .rotationXBy(360) 
  11.                         .rotationY(360) 
  12.                         .rotationYBy(360) 
  13.                         //缩放 
  14.                         .scaleX(1) 
  15.                         .scaleXBy(1) 
  16.                         .scaleY(1) 
  17.                         .scaleYBy(1) 
  18.                         //平移 
  19.                         .translationX(100) 
  20.                         .translationXBy(100) 
  21.                         .translationY(100) 
  22.                         .translationYBy(100) 
  23.                         .translationZ(100) 
  24.                         .translationZBy(100) 
  25.                         //更改在屏幕上的坐标 
  26.                         .x(10) 
  27.                         .xBy(10) 
  28.                         .y(10) 
  29.                         .yBy(10) 
  30.                         .z(10) 
  31.                         .zBy(10) 
  32.                         //监听及其他设置 
  33.                         .setInterpolator(new BounceInterpolator()) 
  34.                         .setStartDelay(1000) 
  35.                         .setListener(new Animator.AnimatorListener() { 
  36.                             @Override 
  37.                             public void onAnimationStart(Animator animation) { 
  38.                             } 
  39.                             @Override 
  40.                             public void onAnimationEnd(Animator animation) { 
  41.                             } 
  42.                             @Override 
  43.                             public void onAnimationCancel(Animator animation) { 
  44.                             } 
  45.                             @Override 
  46.                             public void onAnimationRepeat(Animator animation) { 
  47.                             } 
  48.                         }) 
  49.                         .setUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 
  50.                             @Override 
  51.                             public void onAnimationUpdate(ValueAnimator animation) { 
  52.                             } 
  53.                         }) 
  54.                         .withEndAction(new Runnable() { 
  55.                             @Override 
  56.                             public void run() { 
  57.                                 Log.i(TAG, "run: end"); 
  58.                             } 
  59.                         }) 
  60.                         .withStartAction(new Runnable() { 
  61.                             @Override 
  62.                             public void run() { 
  63.                                 Log.i(TAG, "run: start"); 
  64.                             } 
  65.                         }) 
  66.                         .start(); 

4、添加监听

  1. ViewPropertyAnimator viewPropertyAnimator = gongxiang.animate().setDuration(3000).x(700).y(700).rotation(270).alpha(0.5f).setUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 
  2.     @Override 
  3.     public void onAnimationUpdate(ValueAnimator animation) { 
  4.         ); 
  5.     } 
  6. }).setListener(new AnimatorListenerAdapter() { 
  7.     @Override 
  8.     public void onAnimationCancel(Animator animation) { 
  9.         super.onAnimationCancel(animation); 
  10.     } 
  11.     @Override 
  12.     public void onAnimationEnd(Animator animation) { 
  13.         super.onAnimationEnd(animation); 
  14.         System.out.println("=========onAnimationEnd======="); 
  15.     } 
  16.     @Override 
  17.     public void onAnimationRepeat(Animator animation) { 
  18.         super.onAnimationRepeat(animation); 
  19.     } 
  20.     @Override 
  21.     public void onAnimationStart(Animator animation) { 
  22.         super.onAnimationStart(animation); 
  23.         System.out.println("=========onAnimationStart======="); 
  24.     } 
  25.     @Override 
  26.     public void onAnimationPause(Animator animation) { 
  27.         super.onAnimationPause(animation); 
  28.     } 
  29.     @Override 
  30.     public void onAnimationResume(Animator animation) { 
  31.         super.onAnimationResume(animation); 
  32.     } 
  33. }); 

二、基本原理

1、执行动画基本步骤如下

2、startAnimation()的源码

  1.  
  2. private void startAnimation() { 
  3.     if (mRTBackend != null && mRTBackend.startAnimation(this)) { 
  4.         return
  5.     } 
  6.     mView.setHasTransientState(true); 
  7.     //创建ValueAnimator 
  8.     ValueAnimator animator = ValueAnimator.ofFloat(1.0f); 
  9.     //clone一份mPendingAnimations赋值给nameValueList 
  10.     ArrayList nameValueList = 
  11.             (ArrayList) mPendingAnimations.clone(); 
  12.      //赋值完后清空 
  13.     mPendingAnimations.clear(); 
  14.     //用于标识要执行动画的属性 
  15.     int propertyMask = 0; 
  16.     int propertyCount = nameValueList.size(); 
  17.     //遍历所有nameValuesHolder,取出其属性名称mNameConstant, 
  18.     //执行"|"操作并最终赋值propertyMask 
  19.     for (int i = 0; i < propertyCount; ++i) { 
  20.         NameValuesHolder nameValuesHolder = nameValueList.get(i); 
  21.         propertyMask |= nameValuesHolder.mNameConstant; 
  22.     } 
  23.     //创建PropertyBundle,并添加到mAnimatorMap中 
  24.     mAnimatorMap.put(animator, new PropertyBundle(propertyMask, nameValueList)); 
  25.     if (mPendingSetupAction != null) { 
  26.         //设置硬件加速 
  27.         mAnimatorSetupMap.put(animator, mPendingSetupAction); 
  28.         mPendingSetupAction = null
  29.     } 
  30.     if (mPendingCleanupAction != null) { 
  31.        //移除硬件加速 
  32.         mAnimatorCleanupMap.put(animator, mPendingCleanupAction); 
  33.         mPendingCleanupAction = null
  34.     } 
  35.     if (mPendingOnStartAction != null) { 
  36.         //设置开始的动画(监听器的开始方法中调用) 
  37.         mAnimatorOnStartMap.put(animator, mPendingOnStartAction); 
  38.         mPendingOnStartAction = null
  39.     } 
  40.     if (mPendingOnEndAction != null) { 
  41.         //设置结束后要进行的下一个动画(监听器的结束方法中调用) 
  42.         mAnimatorOnEndMap.put(animator, mPendingOnEndAction); 
  43.         mPendingOnEndAction = null
  44.     } 
  45.     //添加内部监听器 
  46.     animator.addUpdateListener(mAnimatorEventListener); 
  47.     animator.addListener(mAnimatorEventListener); 
  48.     //判断是否延长开始 
  49.     if (mStartDelaySet) { 
  50.         animator.setStartDelay(mStartDelay); 
  51.     } 
  52.     //执行动画的实现 
  53.     if (mDurationSet) { 
  54.         animator.setDuration(mDuration); 
  55.     } 
  56.     //设置插值器 
  57.     if (mInterpolatorSet) { 
  58.         animator.setInterpolator(mInterpolator); 
  59.     } 
  60.     //开始执行动画 
  61.     animator.start(); 

2、PropertyBundle

  1. private static class PropertyBundle { 
  2.         int mPropertyMask; 
  3.         ArrayList mNameValuesHolder; 
  4.         PropertyBundle(int propertyMask, ArrayList nameValuesHolder) { 
  5.             mPropertyMask = propertyMask; 
  6.             mNameValuesHolder = nameValuesHolder; 
  7.         } 
  8.         boolean cancel(int propertyConstant) { 
  9.             if ((mPropertyMask & propertyConstant) != 0 && mNameValuesHolder != null) { 
  10.                 int count = mNameValuesHolder.size(); 
  11.                 for (int i = 0; i < count; ++i) { 
  12.                     NameValuesHolder nameValuesHolder = mNameValuesHolder.get(i); 
  13.                     if (nameValuesHolder.mNameConstant == propertyConstant) { 
  14.                         mNameValuesHolder.remove(i); 
  15.                         mPropertyMask &= ~propertyConstant; 
  16.                         return true
  17.                     } 
  18.                 } 
  19.             } 
  20.             return false
  21.         } 
  22.     } 

PropertyBundle:内部类,存放着将要执行的动画的属性集合信息,每次调用animator.start();

都会将存放在mPendingAnimations的clone一份存入PropertyBundle的内部变量mNameValuesHolder中,然后再将遍历mPendingAnimations中的NameValueHolder类,取出要执行的属性进行”|”操作;

最后记录成一个mPropertyMask的变量,存放在PropertyBundle中,PropertyBundle就是最终要执行动画的全部属性的封装类;

3、AnimatorEventListener

  1. private class AnimatorEventListener 
  2.             implements Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener { 
  3. ... 
  4. ... 

ViewPropertyAnimator内部的监听器:这个类实现了Animator.AnimatorListener, ValueAnimator.AnimatorUpdateListener接口;

这个类还有一个onAnimationUpdate()的监听方法,它是动画执行的关键所在;

4、mAnimatorMap

  1. private HashMap mAnimatorMap = 
  2.         new HashMap(); 

5、onAnimationUpdate

  1. @Override 
  2.         public void onAnimationUpdate(ValueAnimator animation) { 
  3.         //取出当前Animator对应用propertyBundle对象 
  4.             PropertyBundle propertyBundle = mAnimatorMap.get(animation); 
  5.             if (propertyBundle == null) { 
  6.                 // Shouldn't happen, but just to play it safe 
  7.                 return
  8.             } 
  9.         //是否开启了硬件加速 
  10.             boolean hardwareAccelerated = mView.isHardwareAccelerated(); 
  11.             // alpha requires slightly different treatment than the other (transform) properties. 
  12.             // The logic in setAlpha() is not simply setting mAlpha, plus the invalidation 
  13.             // logic is dependent on how the view handles an internal call to onSetAlpha(). 
  14.             // We track what kinds of properties are setand how alpha is handled when it is 
  15.             // setand perform the invalidation steps appropriately. 
  16.             boolean alphaHandled = false
  17.             if (!hardwareAccelerated) { 
  18.                 mView.invalidateParentCaches(); 
  19.             } 
  20.             //取出当前的估算值(插值器计算值) 
  21.             float fraction = animation.getAnimatedFraction(); 
  22.             int propertyMask = propertyBundle.mPropertyMask; 
  23.             if ((propertyMask & TRANSFORM_MASK) != 0) { 
  24.                 mView.invalidateViewProperty(hardwareAccelerated, false); 
  25.             } 
  26.             //取出所有要执行的属性动画的封装对象NameValuesHolder 
  27.             ArrayList valueList = propertyBundle.mNameValuesHolder; 
  28.             if (valueList != null) { 
  29.                 int count = valueList.size(); 
  30.                 //遍历所有NameValuesHolder,计算变化值,并设置给对应的属性 
  31.                 for (int i = 0; i < count; ++i) { 
  32.                     NameValuesHolder values = valueList.get(i); 
  33.                     float value = values.mFromValue + fraction * values.mDeltaValue; 
  34.                     if (values.mNameConstant == ALPHA) { 
  35.                         alphaHandled = mView.setAlphaNoInvalidation(value); 
  36.                     } else { 
  37.                         setValue(values.mNameConstant, value); 
  38.                     } 
  39.                 } 
  40.             } 
  41.             if ((propertyMask & TRANSFORM_MASK) != 0) { 
  42.                 if (!hardwareAccelerated) { 
  43.                     mView.mPrivateFlags |= View.PFLAG_DRAWN; // force another invalidation 
  44.                 } 
  45.             } 
  46.             // invalidate(falsein all cases except if alphaHandled gets set to true 
  47.             // via the call to setAlphaNoInvalidation(), above 
  48.             if (alphaHandled) { 
  49.                 mView.invalidate(true); 
  50.             } else { 
  51.                 mView.invalidateViewProperty(falsefalse); 
  52.             } 
  53.             if (mUpdateListener != null) { 
  54.                 mUpdateListener.onAnimationUpdate(animation); 
  55.             } 
  56.         } 

取出当前Animator对应用propertyBundle对象并获取当前的估算值(插值器计算值),用于后续动画属性值的计算;

从propertyBundle取出要进行动画的属性列表 ArrayList valueList;

遍历所有NameValuesHolder,计算变化值,并通过setValue设置给对应的属性,如果是ALPHA,则会特殊处理一下,最终形成动画效果;

总结

 

年底了,有疫情有裁员,大家要努力,一起加油

 

来源: Android开发编程内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯