在手机chrome搜索灭霸后,会出现一个手套的图片,点击图片后会出现一个彩蛋,即一半的搜索结果会消失。消失的动画如下图所示:
可以看到这个动画 大致可以理解为:将当前view分为两份,每一份同时做透明度动画,并且同时向左想右移动。
先来看下我们实现的效果:
首先是实现的思路:
如何让一个view同时向左右移动呢?我们可以创建两个一模一样的view。但是现在问题来了?如果将原来的view复制一份,合适吗?如果view的层级比较复杂,那么这样做的成本十分巨大。所以我的方案是将当前view的截图保存为Bitmap,然后在一个新的view里创建两个ImageView,将bitmap分别设置给ImageView。然后我们对两个ImageView做动画就可以了。
现在分别看下几个实现细节:
如何拿到View截图
用下面的方法可以拿到对应view的Bitmap,
private Bitmap loadBitmapFromView(View v) {
if (v == null) {
return null;
}
v.setDrawingCacheEnabled(true);
v.buildDrawingCache();
Bitmap bitmap = Bitmap.createBitmap(v.getDrawingCache());
v.setDrawingCacheEnabled(false);
return bitmap;
}
需要注意的是,这里需要用Bitmap.createBitmap(v.getDrawingCache());
来创建一个新的bitmap,而不能直接使用v.getDrawingCache()
,因为使用v.getDrawingCache()
直接创建的bitmap会被回收掉。
RecyclerView如何实现Item动画
RecyclerView可以通过mRecyclerView.setItemAnimator(disappearAnimation);
方法设置Item的动画,Item的动画一共包括四种,分别是add
、remove
、move
、change
。这四种动画分别是指,添加Item、删除Item、Item移动和Item改变的时候。
那么现在问题来了,我们的这个动画适合remove效果吗?使用remove效果的话,需要执行的逻辑比较啊复杂,首先需要将item中的所有子view全部设置为不可见,然后再添加两个ImageView。这样操作的效率太低了。而且添加ImageView的方式根据item根view的layout不同而不同,这样对原有view的侵入型太强。
所以我们选择使用change效果。
最简单的使用方式,是继承DefaultItemAnimator
,然后实现animateChange
方法。但是这样会有一个问题,就是动画效果会出现闪一下的bug,这是由于DefaultItemAnimator
的animateChangeImpl
方法里对新view做了一个透明度变化的动画,而且这个方法是private的,我们不能覆盖。所以我们就不能直接继承于DefaultItemAnimator
。
那么我们的解决方案是自己写一个BaseItemAnimator
,其中的代码大部分与DefaultItemAnimator
相同,但是animateChangeImpl
方法设置为public,这样的话我们就可以在子类覆盖animateChangeImpl
方法,从而随意定制我们的动画。这里仅贴出子类的代码。BaseItemAnimator
的代码太长,可以参阅上面的github地址。
package com.lee.thanos;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.graphics.Bitmap;
import android.view.View;
import android.view.ViewPropertyAnimator;
import androidx.core.view.ViewCompat;
import androidx.core