昨日,小米正式向港交所提交了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 的放大 & 透明度结合的动画,是不是发现使用起来特别简单,一行代码就搞定。
当然,上述的动画效果也可以通过 ValueAnimator 或 ObjectAnimator 来实现,只是可能没法像上述一样一行代码就搞定。如果用 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