Chrome 灭霸打响指彩蛋动画 Android实现
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的动画一共包括四种,分别是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.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实现相关推荐
- python偷回灭霸的宝石_Python视频处理案例:反转灭霸打响指的视频动画(源代码)!...
<复仇者联盟4:终局之战>的宣传口号是逆转无限(to reserve infinity),在电影中,钢铁侠研究出了可以穿越时间的量子战甲,复仇者联盟人手一件,穿越时空回到过去带回了六颗无限 ...
- 尝试用 vue 实现灭霸打响指英雄消失的效果 demo
写在前面 灭霸打响指的消失效果.效果来源于 Google 搜索"灭霸" 或者 "thanos".算是蹭热度的一个 Feature, 我通过 F12 试图去查看是 ...
- Vue灭霸打响指效果
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/GreekMrzzJ/article/details/89821464 </div>< ...
- Problem C 灭霸打响指
Problem Description 那一天,灭霸终于还是集齐了六枚无限宝石,但在打响指消灭一半生命之前,他决定考一考你. 复仇者联盟有n位成员,每位成员的战斗力是si. 灭霸打响指后会消灭一半复仇 ...
- pc模拟微信二维码背景_[深入浅出Windows 10]模拟实现微信的彩蛋动画
9.7 模拟实现微信的彩蛋动画 大家在玩微信的时候有没有发现节日的时候发一些节日问候语句如"情人节快乐",这时候会出现很多爱心形状从屏幕上面飘落下来,我们这小节就是要模拟实现这样的 ...
- [深入浅出Windows 10]模拟实现微信的彩蛋动画
9.7 模拟实现微信的彩蛋动画 大家在玩微信的时候有没有发现节日的时候发一些节日问候语句如"情人节快乐",这时候会出现很多爱心形状从屏幕上面飘落下来,我们这小节就是要模拟实现这样的 ...
- 十分钟实现灭霸打响指灰飞烟灭的效果,android路由器app
//处理canvas的代码 const ctx = canvas.getContext('2d'); const imageData = ctx.getImageData( 0, 0, canvas. ...
- 微博html5版灭霸,十分钟实现灭霸打响指灰飞烟灭的效果
看过复仇者联盟的都知道,灭霸作为计划生育政策的坚定支持者和执行者,一个响指清除了宇宙中二分之一的生命.电影中被清除的生命灰飞烟灭的镜头很是酷炫,所以在复联4上映后,那个不存在的网站google,推出了 ...
- 十分钟实现灭霸打响指灰飞烟灭的效果
看过复仇者联盟的都知道,灭霸作为计划生育政策的坚定支持者和执行者,一个响指清除了宇宙中二分之一的生命.电影中被清除的生命灰飞烟灭的镜头很是酷炫,所以在复联4上映后,那个不存在的网站google,推出了 ...
最新文章
- 单片机干嘛的?嵌入式是单片机吗?
- 制作生成静态页面的新闻系统
- snort2安装及卸载教程
- 基于布隆过滤器实现敏感词识别和过滤
- Linux 高性能服务器编程——socket选项
- 如何避免无意义的区块链项目
- python笔记(五) - 获取对象的引用
- ubuntu14.04/Mint17上Gitolite的搭建过程
- postman post传输中文_Postman:Postman简介、安装、入门使用方法详细攻略
- i3wm nm-applet每次开机都要输入wifi密码的解决办法
- js中this指向学习总结
- oracle软件工程,.Net软件工程师学用Oracle系列(9):系统函数(上)
- BLOB图像处理技术
- IE浏览器主页被hao123等篡改的解决办法
- 谈谈你对promise的理解
- 《提莫必须死》应用隐私政策声明
- 程序设计思维与实践 week10限时模拟 A - 签到题、B - 东东转魔方
- 记一次英伟达驱动踩坑
- 如何按分别率清晰度来计算视频流量?720P 对应按分钟768M
- Dynamo 2.x Essential Training Dynamo 2.x基本训练 Lynda课程中文字幕