一、概念
需要对一个非 View 对象进行操作(如Point对象),而且超出移动、缩放、旋转、透明度的效果需求(如对背景色动态改变),且需要发生真实的改变(补间动画将按钮移到右下角,但点击左上角才会触发),就需要使用属性动画了。
| Android 3.0 之前 传统动画(淘汰别用了) | 视图动画(补间动画)ViewAnimation(Tween):作用对象是 View。只是视觉效果上的改变,并没有修改控件的真实的位置和属性。基于 Framework 的绘制转变。 | |
| 帧动画 DrawableAnimation(Frame):依次播放动画过程中每帧对应的静态图片。 | ||
| Android 3.0 之后 | 属性动画 PeopertyAnimation:View根据执行的动画发生真实的改变,通过不断修改目标的属性值实现。 | |
| 物理动画 DynamicAnimation:使用插值器也能弹来弹去,但轨迹并不符合物理学上的弹跳效果,新的API使用起来也会更加简单。它有两个子类分别是 SpringAnimation(弹簧动画) 和 抛物线动画FlingAnimation(投掷动画)。 | ||
1.1 插值器 Interpolator
即数度模型,作用是控制动画的变化速率,算法对应不同时间点动画完成度的百分比(根据时间流失的百分比来计算属性值改变的百分比),例如实现非线性运动的动画效果(动画改变的速率不是一成不变的,像加速运动以及减速运动)。
对于基于物理特性的动画(加速曲线)需要使用 SpringAnimation(插值器实现起来简单但不符合物理轨迹)。
| LinearInterpolator | 匀速。 |
| AccelerateInterpolator | 持续加速(构造中可调节变速系数)。主要用在出场效果中。 |
| AccelerateDecelerateInterpolator | 先加速再减速。默认效果,最符合现实物理模型。 |
| DecelerateInterpolator | 持续减速到0。主要用于入场效果。 |
| AnticipateInterpolator | 先反效果一点点(平移就是先回拉,放大就是先缩小),再进行正常动画轨迹。 |
| OvershottInterpolator | 超过目标值一些再弹回来。 |
| AnticipateOvershootInterpolator | 两种效果的结合体,先反效果一点点,最后超过目标值一些再回弹。 |
| BounceInterpolator | 在目标值处弹跳几下。 |
| CycleInterpolator | 自定义动画循环播放特定次数。 |
| PathInterpolator | 自定义任何想要的速度模型(动画完成度 ÷ 时间完成度)。使用一个 Path 对象来绘制出想要的曲线(y 为动画完成度,x 为时间完成度)。 |
| FastOutLinearInInterpolator | 持续加速(贝塞尔曲线,初始加速更快,肉眼并不明显)。 |
| FastOutSlowInInterpolator | 先加速再减速(贝塞尔曲线,加速减速更快)。 |
| LinearOutSlowInInterpolator | 持续减速(初始速度更快)。 |
三、属性动画 PeopertyAnimation
3.1 ViewPropertyAnimator
并不是在3.0引入的,而是在3.1作为补充。属性动画不再仅针对于 View 而设计的了,但多数情况下还是对 View 进行动画操作,因此提供了更便捷的用法。
| public ViewPropertyAnimator animate() 通过 view.animate() 返回一个 ViewPropertyAnimator 对象,设置效果后会自动执行,局限性在于只能调用以下方法设置属性动画。 |
3.1.1 动画模式
- 这些方法调用就会执行动画,在播放中途再次调用会先停留在原处,等进度赶上了再继续播放。当动画播放完毕后,不带by的方法再次调用不会执行,任何时候调用 start() 都无效果,调用 cancel() 会打断动画并会停留在原处,再次这些方法等进度赶上了再继续播放。
- 默认动画时长0.3s,通过 setDuration() 自定义。
- 默认速度模型开始加速结束减速(AccelerateDecelerateInterpolator),通过 setInterpolator() 自定义。

textview.animate()
.x(580).y(580)
.setDuration(5000)
.setInterpolator(new BounceInterpolator());
3.1.2 动画监听
| 设置监听 | public @NonNull ViewPropertyAnimator setListener(@Nullable Animator.AnimatorListener listener) 重写onAnimationStart动画开始、onAnimationEnd动画结束、onAnimationCancel动画取消(对应调用了cancel时)、onAnimationRepeat动画重复(对应通过repeat播放时)。 |
| 更新监听 | public @NonNull ViewPropertyAnimator setUpdateListener(@Nullable ValueAnimator.AnimatorUpdateListener listener) 重写onAnimationUpdate每当属性值更新时,参数ValueAnimator可以获取当前动画完成度、属性值等。 |
| 一次性监听 | public @NonNull ViewPropertyAnimator withStartAction(Runnable runnable) public @NonNull ViewPropertyAnimator withEndAction(Runnable runnable) 重用ViewPropertyAnimator 执行别的动画也不会再执行,动画被调用cancel取消时不会再执行。 |
3.3 ObjectAnimator
属性动画的运行机制是通过不断地对值进行操作来实现的,只需要将初始值和结束值提供给 ValueAnimator 并且告诉它动画所需运行的时长,就会自动计算出从初始值平滑地过渡到结束值这样的效果(通过TypeEvaluator,这里是一个FloatEvaluator)。它还负责动画的播放次数、播放模式、以及对动画设置监听器等。ObjectAnimator 就是继承了它。
| ofFloat(Object target, String propertyName, float... values) 通过 ObjectAnimator.ofXXX() 创建对象,XXX具体选什么类型根据该属性设置方法的参数类型决定。target是目标View,propertyName是View的哪个属性(不是找到该名称的属性去设置,而是找到对应的 get/set 方法进行调用,例如 TextView 中并没有 alpha 属性,传入 alpha 就是调用的 setAlpha() 和 getAlpha(),找不到IDE会提示。若是自定义 View 就需要注意提供属性的 get/set 方法(说的就是JAVA写法),并在最后一行调用 invalidate() 触发重绘),values是目标值(填一个就是目标值,填两个就是起始值和目标值,填多个就是增加中间转接点值。若是自定义View,只填一个值的情况就需要该属性提供getter方法,会获取当前值当作起始值)。调用 start() 才会执行动画。 |
class MyView2 : View {
var progress = 0F
set(value) {
field = value
invalidate() //重写getter触发重绘即调用onDraw()
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
canvas?.drawArc(...)
}
}
UI {
val animator = ObjectAnimator.ofFloat(myView, "progress", 0, 65)
animator.start()
}
3.2.1 动画集合
| after(Animator anim) | 将现有动画插入到传入的动画之后执行 |
| after(long delay) | 将现有动画延迟指定毫秒后执行 |
| before(Animator anim) | 将现有动画插入到传入的动画之前执行 |
| with(Animator anim) | 将现有动画和传入的动画同时执行 |
//先从屏幕外移动进屏幕,然后开始旋转360度,旋转的同时进行淡入淡出操作
ObjectAnimator moveIn = 0bjectAnimator.ofFloat(textview, "translationX",-500f,0f);
ObjectAnimator rotate = 0bjectAnimator.ofFloat(textview, "rotation", af, 360f);
ObjectAnimator fadeInOut = 0bjectAnimator.ofFloat(textview, "alpha", 1f, af, 1f);
Animatorset animset =new Animatorset();
animset.play(rotate).with(fadeInOut).after(moveIn);
animset.setDuration(5000);
animset.start();
3.2.2 动画监听
| 设置监听 | public void addListener(AnimatorListener listener) 重写onAnimationStart动画开始、onAnimationEnd动画结束、onAnimationCancel动画取消(对应调用了cancel时)、onAnimationRepeat动画重复(对应通过repeat播放时)。如果不想要这么多监听,可以传入 AnimatorListenerAdapter 对象,它对以上方法都做了空实现,选择重写自己需要的就行。 |
| 更新监听 | public void addUpdateListener(AnimatorUpdateListener listener) 重写onAnimationUpdate每当属性值更新时,参数ValueAnimator可以获取当前动画完成度、属性值等。 |
| 暂停监听 | public void addPauseListener(AnimatorPauseListener listener) |
var boolean = false
onCreate {
//对View启用动画
val animate = imagineView.animate().apply {
//动画类型不能写在里面因为调用就会执行
duration = 2000 //设置动画时长
interpolator = AccelerateDecelerateInterpolator() //设置速度模型
startDelay = 2000 //延迟播放
setListener(object : Animator.AnimatorListener{
override fun onAnimationStart(animation: Animator) { } //动画开始
override fun onAnimationEnd(animation: Animator) { } //动画结束
override fun onAnimationCancel(animation: Animator) { } //动画取消
override fun onAnimationRepeat(animation: Animator) { } //动画重复
})
setUpdateListener { valueAnimator -> } //动画更新
withStartAction { Runnable { } } //动画开始
withEndAction { Runnable { } } //动画结束
}
button1.setOnClickListener {
//中途再次点击会停留在原地等进度赶上了继续播放
animate.translationXBy(200F) //每次点击都有位移效果
animate.rotation(180F) //只执行一次,播放完后再次点击无旋转效果
}
button2.setOnClickListener {
//每次点击在strat和cancel切换,测试结果:start()任何时候都无效,cancel()打断动画停在原地
if (boolean) animate.start() else animate.cancel()
boolean = !boolean
}
}
3.3 TypeEvaluator 类型估值器
就是告诉动画系统如何从初始值过度到结束值。
3.3.1 浮点或整数型计算
//系统内置的FloatEvaluator
//用结束值减去初始值,算出它们之间的差值,然后乘以fraction这个系数,再加上初始值,那么就得到当前动画的值了。
public class FloatEvaluator implements TypeEvaluator {
//参数fraction:表示动画的完成度的,根据它来计算当前动画的值应该是多少
//参数startValue、endValue:动画的初始值和结束值
public Object evaluate(float fraction, Object startValue, object endValue){
float startFloat =((Number)startValue).floatValue();
return startFloat + fraction*(((Number)endValue).floatValue()- startFloat);
}
}
3.3.2 任意对象计算
3.4 TimeInterpolator
兼容之前的 Interpolator。编写自定义Interpolator最主要的难度都是在于数学计算方面的。
| public interface TimeInterpolator { float getInterpolation(float input); } 参数 input 随着动画运行,在开始的0到结束的1之间匀速变化。根据 input 的值来计算出一个返回值,而这个返回值就是 TypeEvaluator 中的 fraction 了。input 和 fraction 相同时动画就是匀速的, |
anim,setInterpolator(new AccelerateInterpolator(2f));
四、切换界面动画 Transition
五、视图动画 ViewAnimation
视图动画的作用对象是View,又叫补间动画,仅仅是呈现呈现效果,便不会改变控件任何的真实情况(例如Button即便动画移到了下边也不能点击,其实还停留在原处可点击)。可以通过 xml 或代码动态创建(建议使用 xml 因为具有更高的可读性和重用性)。
- 数值、百分数、百分数p,譬如50表示以当前View左上角坐标加50px为初始点、50%表示以当前View的左上角加上当前View宽高的50%做为初始点、50%p表示以当前View的左上角加上父控件宽高的50%做为初始点
5.1 动画模式
| 透明度 | AlphaAnimation( float fromAlpha, //动画开始的透明度 float toAlpha //动画结束的透明度 ) 透明度取值范围范围 0~1。 |
| 缩放 | public ScaleAnimation( pivotX/pivotY:缩放的中轴点坐标,即距离自身左边缘的位置,比如50%就是以图像的中心为中轴点。 |
| 平移 | public TranslateAnimation( |
| 旋转 | public RotateAnimation( float pivotY //缩放起点Y坐标 旋转角度:正代表顺时针度数,负代表逆时针度数。 |
| 动画集合 | AnimationSet(boolean shareInterpolator) 可同时播放以上动画。shareInterpolator:true都用一样的插值器,false用各自的插值器。通过调用addAnimation(Animation a) 将动画添加进集合。 |
5.2 动画配置
| 持续时间 | public void setDuration(long durationMillis) |
| 重复次数 | public void setRepeatCount(int repeatCount) 值为-1或者infinite时,表示动画永不停止。 |
| 重复模式 | public void setRepeatMode(int repeatMode) 默认restart,但只有当repeatCount大于0或者infinite或-1时 才有效。还可以设置成reverse,表示偶数次显示动画时会做方向相反的运动。 |
| 设置速度模型 | public void setInterpolator(Interpolator i) |
| 停留结果 | public void setFillAfter(boolean fillAfter) 设为 true 则动画结束后 view 会停留在当前效果。 |
| 开始动画 | public void startAnimation(Animation animation) 由 view 调用,传入要播放的动画。 |
5.3 动画监听
| public void setAnimationListener(AnimationListener listener) 用动画对象调用,重写三个方法:onAnimationStart动画开始时、onAnimationEnd动画结束时、onAnimationRepeat动画重复时。 |
5.4 使用方式
5.4.1 xml配置动画
res目录下新建anim文件夹,创建xml文件,可选节点有alpha、rotate、scale、translate、set。
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromXDelta="0"
android:toXDelta="320"
android:fromYDelta="0"
android:toYDelta="0"
android:duration="2000"/>
AnimationUtils.loadAnimation(this, R.anim.translate) //加载Xml文件中的动画
imagineView.startAnimation(translate) //将动画设置到指定的View上
5.4.2 代码配置动画
val imagineView = binding.imagineView
val button = binding.button
//透明
val alphaAnimation = AlphaAnimation(1.0F, 0.2F)
//旋转
val rotateAnimation = RotateAnimation(0F, 360F, Animation.RELATIVE_TO_SELF, 0.5F, Animation.RELATIVE_TO_SELF, 0.5F)
//缩放
val scaleAnimation = ScaleAnimation(1.0F, 5.0F, 1.0F, 5.0F, Animation.RELATIVE_TO_SELF, 0.5F, Animation.RELATIVE_TO_SELF, 0.5F)
//平移
val translateAnimation = TranslateAnimation(Animation.RELATIVE_TO_PARENT, 0F, Animation.RELATIVE_TO_PARENT, 0F,Animation.RELATIVE_TO_PARENT, 0F, Animation.RELATIVE_TO_PARENT, 0.4F)
//动画集合
val set = AnimationSet(true).apply {
addAnimation(alphaAnimation)
addAnimation(rotateAnimation)
addAnimation(scaleAnimation)
addAnimation(translateAnimation)
duration = 1 //持续时间
repeatCount = 10 //重复次数
repeatMode = Animation.RESTART //重复方式
interpolator = AccelerateDecelerateInterpolator() //速度模型
fillAfter = true //播放完毕后停留在原地
}
//动画监听
set.setAnimationListener(object : AnimationListener {
override fun onAnimationStart(animation: Animation?) { } //动画开始
override fun onAnimationEnd(animation: Animation?) { } //动画结束
override fun onAnimationRepeat(animation: Animation?) { } //动画重复
})
button.setOnClickListener {
imagineView.startAnimation(set) //开始动画
}
六、帧动画 DrawableAnimation(Frame)
容易引起OOM。
6.1 xml配置
res/drawable目录下创建animation-list文件
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false"> //true表示只播放一边,默认就是false可不写
<item android:drawable="@drawable/girl_1" android:duration="100" />
<item android:drawable="@drawable/girl_2" android:duration="100" />
<item android:drawable="@drawable/girl_3" android:duration="100" />
</animation-list>
6.2 代码调用
imagineView.setBackgroundResource(R.drawable.anim_frame)
val animationDrawable = imagineView.background as AnimationDrawable
animationDrawable.start()
文章详细介绍了Android中的属性动画和视图动画,包括补间动画和帧动画的概念,以及属性动画中的插值器和类型估值器。属性动画如ViewPropertyAnimator和ObjectAnimator的使用方法,以及如何设置动画监听和控制动画行为。同时,提到了视图动画的效果和配置,如透明度、缩放、平移和旋转,以及帧动画的配置和使用。
409

被折叠的 条评论
为什么被折叠?



