最近年末了,打算把本身的Android知识都整理一下。html
Android技能书系列:java
Android基础知识android
Android技能树 — View小结github
Android技能树 — View事件体系小结canvas
Android技能树 — Android存储路径及IO操做小结数组
数据结构基础知识
算法基础知识
最近整理了下本身学过的动画方面的知识。用百度脑图作了动画知识的思惟脑图,哪里若是以为不对,你们能够留言提出哦。
你没看错,掘金的文章的图片,电脑上看这种思惟脑图根本就看不清楚,因此我准备一块块来说。 (掘金手机版APP却是能够放大,看的挺清晰的。)
总结的图已经传到了Github上面,能够下载:
动画能够分为两类:Animation 和 Transition二类。
由于通常来讲第二块Animation用的比较多,因此咱们先来看Animation这块:
好的,咱们能够看到咱们的Animation能够分红:
咱们能够按顺序一个个来看:
咱们能够看到,其实View动画很简单,基本使用的是“平移”,“缩放”,“旋转”,“透明度”四种基本动画。
而后咱们看特殊场景下的View动画:
好比:
这里的界面切换动画,与最刚开始的大分类的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()
后面。
也许有人会问,那若是我就是但愿按钮移动到右边后,点击右边的按钮能够有点击事件,你能够选择后面提到的属性动画,或者若是你必定要用View动画,那你能够在右边目标位置,提早准备一个如出一辙的而且隐藏的按钮,而后当左边的按钮移动到右边后,咱们能够设置右边的隐藏的按钮出现,而后把左边的最初的按钮进行隐藏便可。
首先你们能够看下扔物线大佬的相关这个知识点的文章:
HenCoder Android 自定义 View 1-6: 属性动画(上手篇)
【HenCoder Android 开发进阶】自定义 View 1-7:属性动画(进阶篇)
我直接引用了扔物线大佬文章里面的相关动画操做的图片:
用ViewPropertyAnimator 来作属性动画是最简单的。特别方便。
若是想多个动画同时进行,只须要简单的:
view.animate()
.scaleX(1)
.scaleY(1)
.alpha(1);
复制代码
引用扔物线大佬里面的内容:
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在多个动画一块儿进行的时候不能像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
分别执行了。
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();
复制代码
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。
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 进行统一规划和管理,让它们按照要求的顺序来工做。
插值器(Interpolator)和 估值器(Evaluator)你们确定也见过不少次,那这二个究竟是用来干吗的呢?
咱们从头来分析一个平移的动画:
translationX
的属性,让View去移动。那咱们的插值器和估值器是用在哪里呢:
插值器是用在第二步里面,时间经历了N秒,咱们返回一个值,这个值是说明当前动画进行到哪一个程度了。
估值器是用在第三步,咱们已经知道了动画执行到了哪一个程序,而后咱们返回具体的当前变化的数值。
好比咱们来看LinearInterpolator.java
和IntEvaluator.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<Integer>{
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));
}
}
复制代码
过于过渡,我也不费心思所有很详细的写出来,网上的基本介绍及使用有不少。
Android 过渡(Transition)动画解析之基础篇
Activity和Fragment Transition介绍
深刻理解共享元素变换(Shared Element Transition)-上