github地址

在手机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的动画一共包括四种,分别是addremovemovechange。这四种动画分别是指,添加Item、删除Item、Item移动和Item改变的时候。

那么现在问题来了,我们的这个动画适合remove效果吗?使用remove效果的话,需要执行的逻辑比较啊复杂,首先需要将item中的所有子view全部设置为不可见,然后再添加两个ImageView。这样操作的效率太低了。而且添加ImageView的方式根据item根view的layout不同而不同,这样对原有view的侵入型太强。

所以我们选择使用change效果。
最简单的使用方式,是继承DefaultItemAnimator,然后实现animateChange方法。但是这样会有一个问题,就是动画效果会出现闪一下的bug,这是由于DefaultItemAnimatoranimateChangeImpl方法里对新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.view.ViewPropertyAnimatorListener;
import androidx.recyclerview.widget.RecyclerView;class DisappearItemAnimation extends BaseItemAnimator {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;}@Overridepublic void animateChangeImpl(final BaseItemAnimator.ChangeInfo changeInfo) {final RecyclerView.ViewHolder holder = changeInfo.oldHolder;final View view = holder == null ? null : holder.itemView;final RecyclerView.ViewHolder newHolder = changeInfo.newHolder;final View newView = newHolder != null ? newHolder.itemView : null;if (view != null) {final ViewPropertyAnimator oldViewAnim = view.animate().setDuration(getChangeDuration());mChangeAnimations.add(changeInfo.oldHolder);oldViewAnim.translationX(changeInfo.toX - changeInfo.fromX);oldViewAnim.translationY(changeInfo.toY - changeInfo.fromY);oldViewAnim.alpha(0).setListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationStart(Animator animator) {dispatchChangeStarting(changeInfo.oldHolder, true);}@Overridepublic void onAnimationEnd(Animator animator) {oldViewAnim.setListener(null);view.setAlpha(1);view.setTranslationX(0);view.setTranslationY(0);dispatchChangeFinished(changeInfo.oldHolder, true);mChangeAnimations.remove(changeInfo.oldHolder);dispatchFinishedWhenDone();}}).start();}if (newView != null) {newView.setAlpha(1);newView.setTranslationX(0);newView.setTranslationY(0);}if (changeInfo.oldHolder instanceof RecyclerAdapter.ItemViewHolder&& newHolder instanceof RecyclerAdapter.ItemStubViewHolder) {Bitmap bitmap = loadBitmapFromView(changeInfo.oldHolder.itemView);RecyclerAdapter.ItemStubViewHolder stubViewHolder = (RecyclerAdapter.ItemStubViewHolder) newHolder;stubViewHolder.image1.setImageBitmap(bitmap);stubViewHolder.image2.setImageBitmap(bitmap);ViewCompat.animate(stubViewHolder.image1).alpha(0).translationXBy(300).setDuration(2000).start();mChangeAnimations.add(changeInfo.newHolder);ViewCompat.animate(stubViewHolder.image2).alpha(0).translationXBy(-300).setDuration(2000).setListener(new ViewPropertyAnimatorListener() {@Overridepublic void onAnimationStart(View view) {dispatchChangeStarting(changeInfo.newHolder, false);}@Overridepublic void onAnimationEnd(View view) {dispatchChangeFinished(changeInfo.newHolder, false);mChangeAnimations.remove(changeInfo.newHolder);dispatchFinishedWhenDone();}@Overridepublic void onAnimationCancel(View view) {}}).start();}}}

在更新RecyclerView的时候,需要使用notifyItemChanged方法更新。

随机选一半Item

这里提供一种较为简单的方法:每次随机选一个,然后放到Set里,由于Set可以自动去重,随意当Set的大小为原有数据的一半时,那么Set里的数据就是随机一半数据。

    private void randomDisappearAHalf() {if (mList != null && !mList.isEmpty()) {int size = mList.size();HashSet<Integer> set = new HashSet<>();while (set.size() < size / 2) {Random random = new Random();int anInt = random.nextInt(size);set.add(anInt);}for (Integer i : set) {mList.get(i).type = 1;mRecyclerAdapter.notifyItemChanged(i);}}}

Chrome 灭霸打响指彩蛋动画 Android实现相关推荐

  1. python偷回灭霸的宝石_Python视频处理案例:反转灭霸打响指的视频动画(源代码)!...

    <复仇者联盟4:终局之战>的宣传口号是逆转无限(to reserve infinity),在电影中,钢铁侠研究出了可以穿越时间的量子战甲,复仇者联盟人手一件,穿越时空回到过去带回了六颗无限 ...

  2. 尝试用 vue 实现灭霸打响指英雄消失的效果 demo

    写在前面 灭霸打响指的消失效果.效果来源于 Google 搜索"灭霸" 或者 "thanos".算是蹭热度的一个 Feature, 我通过 F12 试图去查看是 ...

  3. Vue灭霸打响指效果

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/GreekMrzzJ/article/details/89821464 </div>< ...

  4. Problem C 灭霸打响指

    Problem Description 那一天,灭霸终于还是集齐了六枚无限宝石,但在打响指消灭一半生命之前,他决定考一考你. 复仇者联盟有n位成员,每位成员的战斗力是si. 灭霸打响指后会消灭一半复仇 ...

  5. pc模拟微信二维码背景_[深入浅出Windows 10]模拟实现微信的彩蛋动画

    9.7 模拟实现微信的彩蛋动画 大家在玩微信的时候有没有发现节日的时候发一些节日问候语句如"情人节快乐",这时候会出现很多爱心形状从屏幕上面飘落下来,我们这小节就是要模拟实现这样的 ...

  6. [深入浅出Windows 10]模拟实现微信的彩蛋动画

    9.7 模拟实现微信的彩蛋动画 大家在玩微信的时候有没有发现节日的时候发一些节日问候语句如"情人节快乐",这时候会出现很多爱心形状从屏幕上面飘落下来,我们这小节就是要模拟实现这样的 ...

  7. 十分钟实现灭霸打响指灰飞烟灭的效果,android路由器app

    //处理canvas的代码 const ctx = canvas.getContext('2d'); const imageData = ctx.getImageData( 0, 0, canvas. ...

  8. 微博html5版灭霸,十分钟实现灭霸打响指灰飞烟灭的效果

    看过复仇者联盟的都知道,灭霸作为计划生育政策的坚定支持者和执行者,一个响指清除了宇宙中二分之一的生命.电影中被清除的生命灰飞烟灭的镜头很是酷炫,所以在复联4上映后,那个不存在的网站google,推出了 ...

  9. 十分钟实现灭霸打响指灰飞烟灭的效果

    看过复仇者联盟的都知道,灭霸作为计划生育政策的坚定支持者和执行者,一个响指清除了宇宙中二分之一的生命.电影中被清除的生命灰飞烟灭的镜头很是酷炫,所以在复联4上映后,那个不存在的网站google,推出了 ...

最新文章

  1. 单片机干嘛的?嵌入式是单片机吗?
  2. 制作生成静态页面的新闻系统
  3. snort2安装及卸载教程
  4. 基于布隆过滤器实现敏感词识别和过滤
  5. Linux 高性能服务器编程——socket选项
  6. 如何避免无意义的区块链项目
  7. python笔记(五) - 获取对象的引用
  8. ubuntu14.04/Mint17上Gitolite的搭建过程
  9. postman post传输中文_Postman:Postman简介、安装、入门使用方法详细攻略
  10. i3wm nm-applet每次开机都要输入wifi密码的解决办法
  11. js中this指向学习总结
  12. oracle软件工程,.Net软件工程师学用Oracle系列(9):系统函数(上)
  13. BLOB图像处理技术
  14. IE浏览器主页被hao123等篡改的解决办法
  15. 谈谈你对promise的理解
  16. 《提莫必须死》应用隐私政策声明
  17. 程序设计思维与实践 week10限时模拟 A - 签到题、B - 东东转魔方
  18. 记一次英伟达驱动踩坑
  19. 如何按分别率清晰度来计算视频流量?720P 对应按分钟768M
  20. Dynamo 2.x Essential Training Dynamo 2.x基本训练 Lynda课程中文字幕

热门文章

  1. Python之综合应用 —— 名片管理系统
  2. java关于zpl打印黑白贴纸图片
  3. 支付宝APP扫一扫领现金
  4. 9.29微信通讯录思维导图
  5. Apache Pig教程_编程入门自学教程_菜鸟教程-免费教程分享
  6. Cocos Creator Animation 组件
  7. 蓝牙耳机哪款质量最好?500元真无线蓝牙耳机推荐
  8. 锐龙r7 6800h和酷睿i7 1260p哪个好 r76800h和i71260p对比
  9. 模糊推理学习笔记及例题
  10. 一维卷积层_使用一维卷积层的创新Chatbot