Android 展开/收回动画效果思路与实现

您所在的位置:网站首页 折叠展开效果 Android 展开/收回动画效果思路与实现

Android 展开/收回动画效果思路与实现

2024-03-27 12:38| 来源: 网络整理| 查看: 265

要实现什么效果?

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

属性动画相关知识 动画执行的逻辑

逻辑大概流程如下:

为 ValueAnimator 设置动画的时长,以及对应属性的始 & 末值设置属性在 始 & 末值 间的变化逻辑 TimeInterpolator实现类:插值器-描述动画的变化速率TypeEvaluator实现类:估值器-描述 属性值 变化的具体数值 根据2中的逻辑更新当前值获取3中更新的值 ,修改目标属性值刷新视图重复4-5,直到 属性值 == 末值 动画工作的关键类 Java类说明ValueAnimator动画执行类,核心。负责动画的整体协调ObjectAnimator动画执行类TimeInterpolator时间插值(插值器接口),控制动画变化率TypeEvaluator类型估值(估值器接口),设置属性值计算方式,根据属性的始末值和插值计算出当前时间的属性值AnimatorSet动画集AnimatorInflater加载属性动画的XML文件 思路分析与实现代码

在这里插入图片描述 首先我们实现这样一个TextView用于展示,实现代码如下:

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

其实思路很简单,就是先将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() { @Override public void onAnimationStart(Animator animation) { super.onAnimationStart(animation); } @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); Timer timer = new Timer(); TimerTask timerTask = new TimerTask() { @Override public 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() { @Override public void onAnimationStart(Animator animation) { super.onAnimationStart(animation); } @Override public 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() { @Override public 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); } 总结

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

点个赞吗?

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



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3