博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android技能树 — 动画小结
阅读量:6218 次
发布时间:2019-06-21

本文共 6988 字,大约阅读时间需要 23 分钟。

最近年底了,打算把自己的Android知识都整理一下。

Android技能书系列:

Android基础知识

数据结构基础知识

算法基础知识

最近整理了下自己学过的动画方面的知识。用百度脑图做了动画知识的思维脑图,哪里如果觉得不对,大家可以留言提出哦。

你没看错,掘金的文章的图片,电脑上看这种思维脑图根本就看不清楚,所以我准备一块块来讲。 (掘金手机版APP倒是可以放大,看的挺清晰的。)

总结的图已经传到了Github上面,可以下载:


动画可以分为两类:Animation 和 Transition二类。

Animation

因为一般来说第二块Animation用的比较多,所以我们先来看Animation这块:

好的,我们可以看到我们的Animation可以分成:

  1. 帧动画
  2. View动画
  3. Property动画(属性动画)

我们可以按顺序一个个来看:

帧动画:

帧动画我就不多说了,就是提前准备好一个连续的图片,然后一张张切换,就类似gif图播放一样。注意点就是图片数量过多并且图片较大,容易出现OOM。

View动画:

1. 四种基本动画:

我们可以看到,其实View动画很简单,基本使用的是“平移”,“缩放”,“旋转”,“透明度”四种基本动画。

2. LayoutAnimation 及 界面切换动画:

然后我们看特殊场景下的View动画:

LayoutAnimaion : 在ViewGroup中,View动画可以用来控制子元素的出场效果,比如我们的应用中的列表,我们在加载列表中的子项的时候,可以让item加载的时候不是突然出现,可以伴随各种动画。

比如:

这里的界面切换动画,与最刚开始的大分类的Transition不同,这里的过渡的动画用的是View动画,比如Activity的切换效果:

//当启动一个Activity时Intent intent = new Intent(this,XXXXX.class);startActivity(intent);overridePendingTransition(R.anim.enter_anim,R.anim.exit_anim);//当Activity退出时@Override public void finish(){    super.finish();    overridePendingTransition(R.anim.enter_anim,R.anim.exit_anim);}复制代码

其中我们可以看到主要是用到overridePendingTransition方法,这个方法必须放在startActivity()finish()后面。

3. View动画注意事项:

这里我们可以看到,View动画其实并不是真得改变了View的状态,比如说我们写了一个按钮,点击按钮可以Toast一段内容,通过Translate动画从左边平移到了右边,这时候虽然按钮看上去在右边了,但是这时候你点击按钮,并不会出现Toast的内容,但是你点击左边的按钮初始位置,却有Toast内容。因为其实按钮只是影像移动过去而已。真正的按钮还是在原始位置。

也许有人会问,那如果我就是希望按钮移动到右边后,点击右边的按钮可以有点击事件,你可以选择后面提到的属性动画,或者如果你一定要用View动画,那你可以在右边目标位置,提前准备一个一模一样的并且隐藏的按钮,然后当左边的按钮移动到右边后,我们可以设置右边的隐藏的按钮出现,然后把左边的最初的按钮进行隐藏即可。

属性动画:

首先大家可以看下扔物线大佬的相关这个知识点的文章:

1. ViewPropertyAnimator:

我直接引用了扔物线大佬文章里面的相关动画操作的图片:

用ViewPropertyAnimator 来做属性动画是最简单的。特别方便。

ViewPropertyAnimator多个动画进行:

如果想多个动画同时进行,只需要简单的:

view.animate()        .scaleX(1)        .scaleY(1)        .alpha(1);复制代码

2. ObjectAnimator:

引用扔物线大佬里面的内容:

动画操作使用方式:
  1. 如果是自定义控件,需要添加 setter / getter 方法;
  2. 用 ObjectAnimator.ofXXX() 创建 ObjectAnimator 对象;
  3. 用 start() 方法执行动画。
public class SportsView extends View {    float progress = 0;    ......    // 创建 getter 方法    public float getProgress() {        return progress;    }    // 创建 setter 方法    public void setProgress(float progress) {        this.progress = progress;        invalidate();    }    @Override    public void onDraw(Canvas canvas) {        super.onDraw(canvas);        ......        canvas.drawArc(arcRectF, 135, progress * 2.7f, false, paint);        ......    }}......// 创建 ObjectAnimator 对象ObjectAnimator animator = ObjectAnimator.ofFloat(view, "progress", 0, 65);// 执行动画animator.start();复制代码

ObjectAnimation多个动画同时进行 - PropertyValuesHolder:

ObjectAnimation在多个动画一起进行的时候不能像ViewPropertyAnimation那样方便,不过你可以使用 PropertyValuesHolder 来同时在一个动画中改变多个属性:

PropertyValuesHolder holder1 = PropertyValuesHolder.ofFloat("scaleX", 1);PropertyValuesHolder holder2 = PropertyValuesHolder.ofFloat("scaleY", 1);PropertyValuesHolder holder3 = PropertyValuesHolder.ofFloat("alpha", 1);ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view, holder1, holder2, holder3)animator.start();复制代码

PropertyValuesHolder 的意思从名字可以看出来,它是一个属性值的批量存放地。所以你如果有多个属性需要修改,可以把它们放在不同的 PropertyValuesHolder 中,然后使用 ofPropertyValuesHolder() 统一放进 Animator。这样你就不用为每个属性单独创建一个Animator 分别执行了。

PropertyValuesHolder - Keyframe:

PropertyValuesHolders.ofKeyframe()把同一个属性拆分 除了合并多个属性和调配多个动画,你还可以在 PropertyValuesHolder 的基础上更进一步,通过设置 Keyframe (关键帧),把同一个动画属性拆分成多个阶段。

例如,你可以让一个进度增加到 100% 后再「反弹」回来。

// 在 0% 处开始Keyframe keyframe1 = Keyframe.ofFloat(0, 0);// 时间经过 50% 的时候,动画完成度 100%Keyframe keyframe2 = Keyframe.ofFloat(0.5f, 100);// 时间见过 100% 的时候,动画完成度倒退到 80%,即反弹 20%Keyframe keyframe3 = Keyframe.ofFloat(1, 80);PropertyValuesHolder holder = PropertyValuesHolder.ofKeyframe("progress", keyframe1, keyframe2, keyframe3);ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view, holder);animator.start();复制代码

3. ValueAnimator:

ViewPropertyAnimator 和 ObjectAnimator的底部都是用ValueAnimator实现的,从字面意思就可以看出是数值的动画,也就是数值的变化。
比如:

ValueAnimator valueAnimator = ValueAnimator.ofInt(1,5);valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {    @Override    public void onAnimationUpdate(ValueAnimator animation) {        int value = (int) animation.getAnimatedValue();//当前的值    }});复制代码

我们可以看到ValueAnimator是监听到当前变化到哪个值了。然后你拿着这个值想怎么处理,就是你的事了。所以ValueAnimator就更基础。

所以你看,ViewPropertyAnimator、ObjectAnimator、ValueAnimator 这三种 Animator,它们其实是一种递进的关系:从左到右依次变得更加难用,也更加灵活。但我要说明一下,它们的性能是一样的,因为 ViewPropertyAnimator 和 ObjectAnimator 的内部实现其实都是 ValueAnimator,ObjectAnimator 更是本来就是 ValueAnimator 的子类,它们三个的性能并没有差别。它们的差别只是使用的便捷性以及功能的灵活性。所以在实际使用时候的选择,只要遵循一个原则就行:尽量用简单的。能用 View.animator() 实现就不用 ObjectAnimator,能用 ObjectAnimator 就不用 ValueAnimator。

4. AnimationSet:

AnimationSet为什么要把这个单独拎出来呢。AnimationSet可以用在多个动画播放,很多人就说了,上面我们在ViewPropertyAnimator 及ObjectAnimation中的PropertyValuesHolder已经可以用在多个动画一起播放了吗?没错,问题就出在这个<一起>这二个字上面,因为上面的二个都是只能N个动画同时播放,比如我现在的需求是先平移,然后平移结束后再放大和改变透明度。而AnimationSet及可以一起播放,又可以控制动画的先后顺序来。

ObjectAnimator animator1 = ObjectAnimator.ofFloat(...);animator1.setInterpolator(new LinearInterpolator());ObjectAnimator animator2 = ObjectAnimator.ofInt(...);animator2.setInterpolator(new DecelerateInterpolator());AnimatorSet animatorSet = new AnimatorSet();// 两个动画依次执行animatorSet.playSequentially(animator1, animator2);animatorSet.start();复制代码

使用 playSequentially(),就可以让两个动画依次播放,而不用为它们设置监听器来手动为他们监管协作。 AnimatorSet 还可以这么用:

// 两个动画同时执行animatorSet.playTogether(animator1, animator2);animatorSet.start();以及这么用:// 使用 AnimatorSet.play(animatorA).with/before/after(animatorB)// 的方式来精确配置各个 Animator 之间的关系animatorSet.play(animator1).with(animator2);animatorSet.play(animator1).before(animator2);animatorSet.play(animator1).after(animator2);animatorSet.start();复制代码

有了 AnimatorSet ,你就可以对多个 Animator 进行统一规划和管理,让它们按照要求的顺序来工作。

5. 插值器 与 估值器

插值器(Interpolator)和 估值器(Evaluator)大家肯定也见过很多次,那这二个到底是用来干嘛的呢?

我们从头来分析一个平移的动画:

  1. 我们告诉一个View,5秒内,从左到右移动500px的距离。
  2. 时间经历到了 N 秒的时候,我们要知道整个动画到了哪个程度,比如动画执行了50% 了。
  3. 当动画执行到某个程序的时候(比如执行了50%),这时候我们的X轴的移动距离的值具体是多少px。
  4. 然后View通过获取到的具体的移动距离的px值,去设置View的translationX的属性,让View去移动。

那我们的插值器和估值器是用在哪里呢:

插值器是用在第二步里面,时间经历了N秒,我们返回一个值,这个值是说明当前动画进行到哪个程度了。
估值器是用在第三步,我们已经知道了动画执行到了哪个程序,然后我们返回具体的当前变化的数值。

比如我们来看LinearInterpolator.javaIntEvaluator.java的原来再理解下:

public class LinearInterpolator implements Interpolator{        public LinearInterpolator(){    }        public LinearInterpolator(Context context,AttributeSet attrs){    }        public float getInterpolation(float input){        //比如时间是5秒,这时候过了2.5秒,这时候时间流逝了0.5,所以input是0.5        //因为我们这个LiearInterpolator是线性插值器,        //所以时间流失了0.5,我们的动画的动画也执行了0.5(也就是完成了50%的程度)        //所以这里直接返回input即可。        return input;    }    }复制代码
public class IntEvaluator implements TypeEvaluator
{ public Integer evaluate(float fraction,Integer startValue,Integer endValue){ //fraction就是我们上面插值器返回的,告诉我们动画执行到什么程度了。 //startValue是我们起始值,endValue是我们最后的目标值。 //比如我们是ofInt(0,500);这时候我们return的值就是(0+0.5 * (500-0))= 250 int startInt = startValue; return (int)(startInt + fraction * (endValue - startValue)); }}复制代码

Transition

过于过渡,我也不费心思全部很详细的写出来,网上的基本介绍及使用有很多。

基本知识:

稍微深度过渡动画基本原理:

这里我也用过渡写过相关效果的文章:

转载地址:http://yulja.baihongyu.com/

你可能感兴趣的文章
Python工具分析风险数据
查看>>
Git自由之章 - 关于SSH 公钥
查看>>
关于classpath中有多个同名类或一个接口有多个实现类Spring启动失败总结
查看>>
数组reduce方法的高级技巧
查看>>
pt-online-schema-change使用说明、限制与比较
查看>>
一些小技巧让JS代码更优雅
查看>>
jquery 添加和删除html元素
查看>>
Java 8怎么了之二:函数和原语
查看>>
dingo/api 使用
查看>>
PHP字符串函数之 strstr stristr strchr strrchr
查看>>
mac安装docker
查看>>
Objective-C runtime 拾遗 (二)——Log message send
查看>>
【temp】Graphx Visualization
查看>>
[LeetCode]Maximal Rectangle
查看>>
JavaScript-imooc
查看>>
[LintCode] Find the Missing Number [三种方法]
查看>>
elasticsearch搭建
查看>>
使用python解释设计模式[译]
查看>>
对立即数进行位移引发的小问题
查看>>
位置行业应用开发应该如何选择GPS定位系统
查看>>