要实现什么效果?


我们就是要实现如图所示的动画效果,在开始之前我们先了解一下实现这个动画的相关知识。

属性动画相关知识

动画执行的逻辑

逻辑大概流程如下:

  1. 为 ValueAnimator 设置动画的时长,以及对应属性的始 & 末值
  2. 设置属性在 始 & 末值 间的变化逻辑
  • TimeInterpolator实现类:插值器-描述动画的变化速率
  • TypeEvaluator实现类:估值器-描述 属性值 变化的具体数值
  1. 根据2中的逻辑更新当前值
  2. 获取3中更新的值 ,修改目标属性值
  3. 刷新视图
  4. 重复4-5,直到 属性值 == 末值

动画工作的关键类

Java类 说明
ValueAnimator 动画执行类,核心。负责动画的整体协调
ObjectAnimator 动画执行类
TimeInterpolator 时间插值(插值器接口),控制动画变化率
TypeEvaluator 类型估值(估值器接口),设置属性值计算方式,根据属性的始末值和插值计算出当前时间的属性值
AnimatorSet 动画集
AnimatorInflater 加载属性动画的XML文件

思路分析与实现代码


首先我们实现这样一个TextView用于展示,实现代码如下:

<TextViewandroid:id="@+id/tv_left"android:layout_width="wrap_content"android:layout_height="60dp"android:layout_gravity="end"android:layout_marginTop="30dp"android:background="@drawable/circleside"android:gravity="center_vertical"android:maxLines="1"android:paddingLeft="16dp"android:paddingRight="16dp"android:text="青柠天气提醒您,天冷注意添加衣"android:textSize="17sp" />

其中的@drawable/circleside 代码如下:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >  <!-- 填充颜色 -->  <solid android:color="#40FF552E"></solid>  <!-- 矩形的圆角半径 --> <corners android:bottomLeftRadius="999dp" android:topLeftRadius="999dp"></corners>
</shape>

其实思路很简单,就是先将View的宽度设置为0,随着时间的增多逐渐把View的宽度设置为它应该有的宽度即可。

private ValueAnimator createDropAnimator(final View v, int start, int end) {ValueAnimator animator = ValueAnimator.ofInt(start, end);animator.addUpdateListener(arg0 -> {int value = (int) arg0.getAnimatedValue();ViewGroup.LayoutParams layoutParams = v.getLayoutParams();layoutParams.width = value;v.setLayoutParams(layoutParams);});return animator;}

首先我们构建一个ValueAnimator,添加了一个UpdateLisenter的方法,这个方法是在动画开始后返回值来让我们进行处理的,这个方法我们传入了三个参数分别是View,start,end,分别代表了我们创建的那个TextView,动画开始的宽度,最终的宽度。我们在updateListener里对view的宽度进行的修改。

private void show(View view, int tvWidth, long delay) {view.setVisibility(View.VISIBLE);ValueAnimator valueAnimator = createDropAnimator(view, 0, tvWidth);valueAnimator.setDuration(500);valueAnimator.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationStart(Animator animation) {super.onAnimationStart(animation);}@Overridepublic void onAnimationEnd(Animator animation) {super.onAnimationEnd(animation);Timer timer = new Timer();TimerTask timerTask = new TimerTask() {@Overridepublic void run() {runOnUiThread(() -> disMiss(view, tvWidth));}};timer.schedule(timerTask, delay);}});valueAnimator.start();}

这个是触发动画的方法,第三行调用了上述的ValueAnimator的构建方法,从0到width的一个变化过程。在打开动画结束后我们又延时delay ms调用了dismiss方法来把view收起来。

private void disMiss(View view, int tvWidth) {ValueAnimator valueAnimator = createDropAnimator(view, tvWidth, 0);valueAnimator.setDuration(500);valueAnimator.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationStart(Animator animation) {super.onAnimationStart(animation);}@Overridepublic void onAnimationEnd(Animator animation) {view.setVisibility(View.GONE);}});valueAnimator.start();}

dismiss方法的思路和show的差不多,只不过是从width到0的一个过程。

进过上述的3个方法我们的动画基本上已经完成了

要踩的坑

1. show()方法何时调用(动画)何时开始?

如果你在onCreate里调用show方法,动画播放的过程是这样的。等你看见View的时候动画已经播放到一半了,为什么会这样?我们要了解Activity的生命周期。
onCreate和onStart调用之后我们还不能看见Activity的视图,所以调用之后动画已经绘制了一半了我们还没有看见。那我们放在onResume里再调用不就可以了吗?这样做可以,但是还是有问题,因为我们进入Activity时是有动画的,这个动画是和我们的动画一起执行的,所以还是会有可能看不全的(概率较小)。这里我们就要引入一个监听了,代码如下:

ViewTreeObserver viewTreeObserver = getWindow().getDecorView().getViewTreeObserver();viewTreeObserver.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {@Overridepublic boolean onPreDraw() {show(mTextView,tvWidth,1000);getWindow().getDecorView().getViewTreeObserver().removeOnPreDrawListener(this::onPreDraw);return true;}});

这个方法监听了onDraw方法,在onDraw执行之前就会调用这个show方法保证我们的动画播放完全。

2.为什么横幅(View)有时候会闪一下?

有时候View会闪,就是因为View本来就是VISIBLE的,动画开始的时候回突然把view的宽度置为0,所以会闪一下。如何解决这个问题呢?答案就一句话:

在XML里把View的可见性设置为INVISIBLE或者GONE

3.这个TVWidth(View的宽度)如何获得呢?

众所周知,在OnCreate里是无法获取View的真实宽高的,那我们要如何解决这个问题呢?有人要说了,我百度了,用第一个问题里的监听方法就可以获取宽高。可是这个动画里你能获取到吗?答案是不能,第二个问题里我们已经把View的可见性设置为INVISIBLE或者GONE了,这两个方法View是不会绘制的,所以你根本无法获得View的宽高,那怎么解决呢?答案就是两个字:

计算

tvWidth = ScreenUtils.dip2px(this, (float) (paddingLeft + paddingRight)) +ScreenUtils.sp2px(this, (float) ( 17))*s.length();

这里我提供了一个简单的思路,View的宽度就是paddingLeft + paddingRight + 字的宽度;看这个计算方法应该非常简单了。下面是ScreenUtils的三个方法:

    public static int dp2px(Context context, float dpValue) {float scale = context.getResources().getDisplayMetrics().density;return (int) (dpValue * scale + 0.5F);}public static int px2dp(Context context, float pxValue) {float scale = context.getResources().getDisplayMetrics().density;return (int) (pxValue / scale + 0.5F);}public static int sp2px(Context context, float spValue) {final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;return (int) (spValue * fontScale + 0.5f);}

总结

至此,我们已经实现了这个简单的展开收回动画,简单易懂,如果可以的话可以帮我

点个赞吗?

如果有不懂的也可以在评论里问我,下次见拜拜!

Android 展开/收回动画效果思路与实现相关推荐

  1. Android 卡片翻转动画效果

    转载请标明出处:http://blog.csdn.net/android_mnbvcxz/article/details/78570594 Android 卡片翻转动画效果 前言 前端时间开发一款应用 ...

  2. 右上角鼠标滑过展开收缩动画效果js代码的演示页面

    http://files.cnblogs.com/files/tanlingdangan/top_right.rar.gz 右上角鼠标滑过展开收缩动画效果js代码的演示页面http://www.51x ...

  3. Android中具有动画效果的图片资源

    Android动画和Transition系列文章 初识属性动画--使用Animator创建动画 再谈属性动画--介绍以及自定义Interpolator插值器 三谈属性动画--Keyframe以及Vie ...

  4. 【Android笔记25】Android中的动画效果之逐帧动画

    这篇文章,主要介绍Android中的动画效果之逐帧动画. 目录 一.逐帧动画 1.1.什么是逐帧动画 1.2.逐帧动画的使用 (1)创建drawable动画资源<

  5. Android颜色渐变动画效果的实现

    系列文章目录 Android颜色渐变动画效果的实现 文章最后有源码 文章目录 系列文章目录 前言 一.Android中插值器TypeEvaluator. 二.案例效果实现 1.利用Android自带的 ...

  6. android图片gif动画效果,android中类似于gif 实现图片的动画效果

    案例:实现gif动画效果,连续播放图片 由于是转载的,也就没必要多说,直接上代码 案例:在android中实现gif动态图片的效果: EarthAnimationActivity.java packa ...

  7. android属性动画作用范围,Android开发之动画效果浅析(一)

    程序运行效果图: Android动画主要包含补间动画(Tween)View Animation.帧动画(Frame)Drawable Animation.以及属性动画Property Animatio ...

  8. Lottie 站在巨人的肩膀上实现 Android 酷炫动画效果

    说到动画效果,一般都会感到很高端,感觉很酷炫:而小菜技术有限,稍复杂的动画效果也需要很多时间处理,但是遇到时间紧任务重的情况该怎么办呢?那就尝试一下 Lottie 吧,酷炫的动画集成却相当简单,还支持 ...

  9. Android 雪花飘落动画效果 自定义View

    在码农的世界里,优美的应用体验,来源于程序员对细节的处理以及自我要求的境界,年轻人也是忙忙碌碌的码农中一员,每天.每周,都会留下一些脚印,就是这些创作的内容,有一种执着,就是不知为什么,如果你迷茫,不 ...

最新文章

  1. python函数调用的例子_实例讲解Python中函数的调用与定义
  2. python怎么编辑文件夹_python创建修改文件
  3. 安装目录opencv for android 教程(环境搭建篇)
  4. 六、Springmvc json数据交互
  5. IDEA中Mybatis逆向工程使用方法
  6. 如何对Javascript代码进行二次压缩(混淆)
  7. BZOJ 1878: [SDOI2009]HH的项链 | 莫队
  8. crack翻译成中文_crack是什么意思_crack在线翻译_英语_读音_用法_例句_海词词典
  9. linux中关于ssh实验,操作系统实验三linux的telnetftpssh的相关配置及验证
  10. 文件源路径太长无法删除
  11. 小米笔记本Pro ubuntu 18.04安装显卡驱动
  12. 用互联网思维去做事之-(2)用户思维
  13. android Manifest介绍
  14. c++ 线程进度条_AMD R9 5900X 跑分曝光,单线程性能大幅提升;天猫“官宣”苹果iPhone 12:暗示10月16日开启预定...
  15. android 手机 otg,对于安卓智能手机的OTG功能,你了解多少
  16. 第四章 linux字符设备的编写一
  17. 出现ConnectionError: Error 10061 connecting to 127.0.0.1:6379. 由于目标计算机积极拒绝,无法连接的解决方法
  18. 大学期末考java编程题_大学慕课2020年Java程序设计期末考试大全答案
  19. 台达DVP-EH3系列PLC如何实现远程编程调试和程序上下载?
  20. Android加载超长图(微博长图)

热门文章

  1. centos7安装rebar3
  2. 上班族适合的兼职副业有哪些
  3. 系统装完以后无法启动计算机,系统重装后不能启动的解决方法
  4. 解构微信(二):团队是研究院、艺术中心甚至学校
  5. 采集百度图片不显示 怎么办
  6. LR(0)项目集规范族和分析表的构造
  7. 大学计算机基础的教案,《大学计算机基础》教案.docx
  8. 深度补偿模型sparse-to-dense测试
  9. 计算机实验以太网桢分析,计算机网络实验2 分析 Ethernet帧.
  10. Python王牌加速库:奇异期权定价的利器!