Android中动画的使用 前言: 在Android中,如果想让一个View的消失,如果没有做任何处理,直接setVisibility(View.GONE)
,你会发现整个View是瞬间消失的,没有任何过度。为了让用户感知到View的消失,就要让这个View消失的时候带一个动画效果,这样可以减轻用户的焦虑感。
Android中动画的种类 Android中共有三种动画系统,分别是:
View Animations - 最原始的Android动画,性能差而且不够灵活.Property Animations动画出现后就被废弃了。
Property Animations - 自Android 3.0后引入的强大灵活的动画系统
Transition Animations - 上面两种动画只是对某个View进行改变,而不会影响其所在的容器及周边的Views,而Transition动画可以适应layout的变化。默认的Transition框架支持Andorid 4.4以上的系统,使用com.android.support:transition
支持库可以使Transition框架兼容到Android 4.0及以上。
Property Animation 属性动画 其中我们最常用的是Property animation ,称之为,属性动画。顾名思义,属性动画可以对任意对象的任意属性在一段时长内进行渐变:
Property animations allow us to animate any property of any object from one value to another over a specified duration.
所以,属性动画除了可以对View的位置、角度做变换外,还可以对字体的大小、View的颜色等属性进行变换。
Android中常用的动画叫Property Animation(属性动画) ,它是出现在View Animation(视图动画) (包括 Tween Animation(补间动画)和 Frame Animation(逐帧动画)) 之后的,相比老的视图动画,Property Animation的主要优势是:
老的View Animation只是对View对象的外观进行动画操作,但是并没有真正的改变对象本身的属性。例如对某个View平移以后,只是视觉特效,并没有真正改变这个View的位置,也就是说你点击平移后的View是不能触发onClick的,因为其属性中的位置还在原来的位置(the previous animations changed the visual appearance of the target objects… but they didn’t actually change the objects themselves.)。而Property Animation除了视觉效果,还能真正的改变View的属性。而使用Property Animation不仅可以对View进行透明度渐变、缩放、平移操作,还可以对其他的一些属性 进行动画操作,例如字体大小,颜色,背景等,实现炫酷的字体颜色变化,或者背景颜色变化等等。
Property Animation(属性动画)的主要实现类是:ObjectAnimation。这个类是我们实现动画最常用的类。
ObjectAnimator 动画 用法示例 ObjectAnimator的主要用法如下,假设要让一个View进行透明度从透明到不透明:
1 ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(view,"Alpha" , 0f , 1f ) .setDuration(getResources().getInteger(R.integer.china_date_switch_btn_gone_duration));
上面代码中ofFloat就是指让这个动画按照float类型的精度去变化。ofFloat函数源码中的常用构造函数如下:
1 ofFloat(Object target, String propertyName, float ... values)
第一个target是要赋予动画的对象,第二个propertyName是赋予什么动画或者对这个对象的什么属性进行变化,第三个是一个可变长度的参数,那三个点表示这个参数可以有多个,例如上面示例代码中有两个,分别是0f和1f,表示从透明变到不透明。也可以添加任何多个,例如0f, 1f, 0.5f,指的就是从透明到不透明又到半透明。
上面简单的例子就实现了透明度动画。除了透明度属性,常用的属性还有:
常用的propertyName有以下:
| 属性 | 作用 | 数值类型 |
| ———— | ——————————— | ——– |
| Alpha | 控制View的透明度 | float |
| TranslationX | 控制X方向的位移(相对于当前位置) | float |
| TranslationY | 控制Y方向的位移(相对于当前位置) | float |
| ScaleX | 控制X方向的缩放倍数 | float |
| ScaleY | 控制Y方向的缩放倍数 | float |
| Rotation | 控制以屏幕方向为轴的旋转度数 | float |
| RotationX | 控制以X轴为轴的旋转度数 | float |
| RotationY | 控制以Y轴为轴的旋转度数 | float |
除了上面的属性,ObjectAnimator可以对一个对象的任意属性进行动画渐变,例如:
1 2 3 ObjectAnimator.ofFloat(mTextView,"textSize" , 0 , 100 , 50 ) .setDuration(5000 ) .start();
这样就相当于不断调用TextView的setTextSize()方法对文字大小进行设置,就实现字体变大,再变小的动画。
但是需要注意的是,如果要对一个对象的属性进行变化,这个对象必须有公开的set
的方法例如TextView有setTextSize这个方法,那么就可以用“textSize”这个属性。
这时你可能会疑惑了🤔,如果想控制的对象方法名字不是set开头,而是叫changeTextSize或者moveXPosition等,或者一个对象有set方法,但是没有public暴露给大家使用怎么办呢?
这时可以提出两种抛砖引玉的方法:
在对象外层包装一个类,自己写一个public的set方法控制对象的属性。
使用ValueAnimator。至于什么是ValueAnimator,下面就马上会讲到。
ValueAnimator 明白了怎么用,我们再简单了解一下它实现的原理,想一想怎样实现对象的属性动画呢?如果我们想实现一个1秒钟内将透明度从0变到1的动画,其实是把整个工作分成了两部分:
其实ValueAnimator就是一个时间机制,你甚至可以单纯的利用它的时间机制实现除了动画以外的其他逻辑:
1 2 3 4 5 6 7 8 9 ValueAnimator anim = ValueAnimator.ofFloat(0f , 1f );anim.setDuration(500 ); anim.addUpdateListener(new ValueAnimator .AnimatorUpdateListener() { public void onAnimationUpdate (ValueAnimator animation) { Float value = (Float) animation.getAnimatedValue(); } }); anim.start();
AnimatorSet 如果需要组合多个动画,可以借助AnimatorSet
进行统一管理。AnimatorSet类可以将单个的ObjectAnimator组合起来形成动画集,可以同时创建多个特效,例如,一边放大一边变透明化或者按照顺序先放大再透明化等等。通过组合不同的动画属性,可以满足生活中大部分常用的场景。其用法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(view,"Alpha" , 0f , 1f ) .setDuration(getResources().getInteger(R.integer.china_date_switch_btn_gone_duration)); ObjectAnimator scaleAnim = ObjectAnimator.ofFloat(view,"scaleY" , 0 , 1 ) .setDuration(getResources().getInteger(R.integer.china_date_switch_btn_gone_duration)); AnimatorSet fadeInAnim = new AnimatorSet ();fadeInAnim.play(alphaAnim).with(scaleAnim); fadeInAnim.addListener(new AnimatorListenerAdapter () { @Override public void onAnimationStart (Animator animation) { super .onAnimationStart(animation); view.setVisibility(View.VISIBLE); } }); fadeInAnim.start();
两大神器TypeEvaluator和Interpolation TypeEvaluator 恐怕不少刚接触ObjectAnimator的人都会想为啥ObjectAnimator后面要跟ofFloat, ofInt和ofObject,ofObject又是个什么东西呢?
如果一个动画变化的属性是数字,例如透明度就是从0到1的,ofFloat会在要求的时间范围内把每个时间点的值计算成一个个的float值,相应的,ofInt就会把属性值计算成Int值,这些都是动画系统实现的方法。那如果现在属性的变化不是时间而是Point类,那动画系统怎么知道如何计算每个时间点的Point值呢,答案是你来告诉动画系统如何计算。只要继承TypeEvaluator类,实现其中的evaluate方法即可:
1 2 3 4 5 6 7 8 public class PointEvaluator implements TypeEvaluator { public Object evaluate (float fraction, Object startValue, Object endValue) { Point startPoint = (Point) startValue; Point endPoint = (Point) endValue; return new Point (startPoint.x + fraction * (endPoint.x - startPoint.x), startPoint.y + fraction * (endPoint.y - startPoint.y)); } }
这样就可以计算两个点之间的值了:
1 2 3 Point p0 = new Point (0 , 0 );Point p1 = new Point (100 , 200 );ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator (), p0, p1);
Interpolation 放大,缩小,平移等这样的动画方式非常普通,因为这些动画是线性的,也就是说在动画时间内,属性值的变化是线性变化的。大家有时会看到一些非常炫酷的动画例如,回弹,果冻效果等等,这些效果多是非线性变化的结果,如果想实现这样的效果,就用到了Interpolation(插值器)。
Android已经实现了常用的Interpolation,如:
| Name | Description |
| ———————- | ———– |
| AccelerateInterpolator | 加速 |
| BounceInterpolator | 弹跳 |
| DecelerateInterpolator | 减速 |
还有AccelerateDecelerateInterpolator、AnticipateInterpolator、PathInterpolator、OvershootInterpolator、AnticipateOvershootInterpolator 、DecelerateInterpolator 、CycleInterpolator等,这些基本上涵盖了我们使用的范围。
当然,如果上面插值器不满足需求,也可以定制插值器,只需要继承BaseInterpolator并实现TimeInterpolator接口就可以了,例如OvershootInterpolator的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class OvershootInterpolator extends BaseInterpolator { private final float mTension; public OvershootInterpolator () { mTension = 2.0f ; } public OvershootInterpolator (float tension) { mTension = tension; } public float getInterpolation (float t) { t -= 1.0f ; return t * t * ((mTension + 1 ) * t + mTension) + 1.0f ; } }
这里的getInterpolation方法里是一个插值器函数,如果输入的t直接返回,那这就是一个线性插值器。这个网站 看一查看插值器函数生成的曲线,安利给大家。
Android Transition Framework 上面介绍的动画针对的是某一个对象进行动画操作,但是实际应用中,我更多的使用Android的Transition动画来移动某个View。Transition动画与Property动画最大的区别就是:View动的过程中会对其周边的View产生影响。也就是说,如果我想让一个View逐渐变大,那它在变大的过程中不会覆盖在其周边的View上面,而是挤推着周围的View移动,也就是整个Layout都在变化,而这一切都是Transition框架自动实现的,开发者不需要关心实现细节。
后续补充:
https://developer.android.com/training/transitions/
https://developer.android.com/training/transitions/start-activity
https://cloud.tencent.com/info/8fb508a6e6115e59e4f151fbaadd432e.html
参考: ObjectAnimator 基本使用 http://wiki.jikexueyuan.com/project/android-animation/7.html
Android 属性动画:这是一篇很详细的 属性动画 总结&攻略 https://blog.csdn.net/carson_ho/article/details/72909894
为什么要废弃掉Android之前的动画?https://android-developers.googleblog.com/2011/02/animation-in-honeycomb.html
查看Interpolation曲线:http://inloop.github.io/interpolator/