View.animate()一一简单快速实现动画效果

本文深入探讨了 Android 中 View.animate() 的工作原理,通过源码分析揭示了其如何实现动画效果。文章指出,即使不调用 start(),ViewPropertyAnimator 也会在下一帧自动启动动画。文章详细阐述了 ViewPropertyAnimator 如何借助 ValueAnimator 在每一帧的回调中更新 View 的属性来实现动画,并讨论了多个动画同时运行的管理机制。此外,文章留下了两个问题:在 RecyclerView 中使用 View.animate() 时可能出现的动画中断问题,以及 mRenderNode 对象如何修改 View 属性实现动画效果。
摘要由CSDN通过智能技术生成

640?wx_fmt=png&wxfrom=5&wx_lazy=1


今日科技快讯


昨日,小米正式向港交所提交了IPO申请,招股书主要显示以下几点:

1. 小米2015年小米净亏损3.0亿元、2016年净利润19.0亿元,2017年净利润53.6亿元;

2. 截止2018年3月31日,小米投资或孵化超过210家公司;

3. 小米海外销售额达321亿元,占小米总收入的28.0%;

4. 截至2018年3月31日,小米已获得中国国家知识产权局3600多项授权专利。已在多个海外国家及司法权区注册3500多项专利,并有5800多项专利申请正在受理中。


作者简介


明天就是周六啦,提前祝大家周末愉快。

本篇来自老司机 请叫我大苏 的投稿,分享了他对 View.animate() 这一系列方法的源码分析,希望对大家有所帮助!

请叫我大苏 的博客地址:

https://www.jianshu.com/u/bb52a2918096


前言


这次想来讲讲 View.animate(),这是一种超好用的动画实现方式,用这种方式来实现常用的动画效果非常方便,但在某些场景下会有一个坑,所以这次就来梳理一下它的原理。


基础


首先,先来看一段代码:

mView.animate().sacleX(1.2f).scaleY(1.2f).alpha(0.5f).setDuration(1000).start();  

可以有些人还没接触过这个,但并不妨碍首次理解上述代码。单从方法名上来看,上述代码就是一个实现了持续 1s 的放大 & 透明度结合的动画,是不是发现使用起来特别简单,一行代码就搞定。

当然,上述的动画效果也可以通过 ValueAnimatorObjectAnimator 来实现,只是可能没法像上述一样一行代码就搞定。如果用 Animation 来实现,那么需要的代码就更多了。

所以,我们的问题就来了:

Q1:动画基本可以分为 Animator 和 Animation 两大类,而 View.animate() 返回的是一个 ViewPropertyAnimator 类型的对象,这个类并没有继承自任何类,那么它实现动画的原理又是什么呢?单从命名上看好像是通过 Animator 实现,那么真的是这样么?

Q2:开头说了,使用这种方式实现的动画在某些场景下会有一个坑,这个坑又是什么,是在什么场景下的呢?

好了,下面就开始来跟着源码一起学习吧:


源码分析


ps:本篇阅读的源码版本都是 android-25,版本不一样,源码可能会有些许差别,大伙自己过的时候注意一下。

那么,源码阅读的着手点就跟之前几篇分析动画的一样,从 start() 开始一步步跟踪下去就行了。

//ViewPropertyAnimator#start()
public void start() {
   mView.removeCallbacks(mAnimationStarter);
   startAnimation();
}

代码很少就两行,第二行是调用了一个方法,看方法名可以猜测应该是去处理动画开始的工作,那么在动画开始前还移除了一个回调,但要搞清楚第一行的代码是干嘛用的,我们得先知道两个变量的含义,首先是第一个 mView:

//ViewPropertyAnimator构造函数
ViewPropertyAnimator(View view) {
   mView = view;
   view.ensureTransformationInfo();
}

mView 是一个成员变量,在构造函数中被赋值,还记得吧,要用这种方式实现动画时,都得先调用 View.animate() 来创造一个 ViewPropertyAnimator 对象,所以去 View 的 animate() 方法里瞧瞧:

//View#animate() 
public ViewPropertyAnimator animate() {
   if (mAnimator == null) {
       mAnimator = new ViewPropertyAnimator(this);
   }
   return mAnimator;
}

这个方法里会去创建一个 ViewPropertyAnimator 对象,并将 View 自身 this 作为参数传递进去,也就是说,在 ViewPropertyAnimator 里的 mView 变量其实指向的就是要进行动画的那个 View。

知道了 mView 其实就是需要进行动画的那个 View 后,接下去来看看另一个变量 mAnimationStarter 是什么了:

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

这个 Runnable 就是一个启动动画的工作,emmm,这样就有点奇怪了,我们再回过头来看看 start() 方法:

//ViewPropertyAnimator#start()
public void start() {
   mView.removeCallbacks(mAnimationStarter);
   startAnimation();
}

为什么明明方法的第二行就会去执行 startAnimation() 了,第一行却又要去取消一个执行 startAnimation() 的 Runnable 呢?

只能说明,在我们调用 start() 之前,ViewPropertyAnimator 内部就已经预先安排了一个会执行 startAnimation() 的 Runnable 进入待执行状态,所以在调用了 start() 之后先去取消这个 Runnable 才会有意义。

那么,又是哪里会去触发安排一个 Runnable 呢?

回头再看看我们使用这种方式来实现动画效果是怎么用的:

mView.animate().sacleX(1.2f).scaleY(1.2f).alpha(0
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值