一、概念
属性动画PeopertyAnimation:view的属性根据执行的动画发生真实的改变。通过不断设置 View 的属性实现。 |
补间动画 ViewAnimation(Tween):不改变view的位置和属性。基于 Framework的绘制转变。 |
帧动画 DrawableAnimation(Frame):依次播放动画过程中每帧对应的静态图片。 |
二、插值器 Interpolator
即数度模型,算法对应不同时间点动画完成度的百分比。
LinearInterpolator | 匀速。 |
AccelerateInterpolator | 持续加速(构造中可调节变速系数)。主要用在出场效果中。 |
AccelerateDecelerateInterpolator | 先加速再减速。默认效果,最符合现实物理模型。 |
DecelerateInterpolator | 持续减速到0。主要用于入场效果。 |
AnticipateInterpolator | 先反效果一点点(平移就是先回拉,放大就是先缩小),再进行正常动画轨迹。 |
OvershottInterpolator | 超过目标值一些再弹回来。 |
AnticipateOvershootInterpolator | 两种效果的结合体,先反效果一点点,最后超过目标值一些再回弹。 |
BounceInterpolator | 在目标值处弹跳几下。 |
CycleInterpolator | 自定义动画循环播放特定次数。 |
PathInterpolator | 自定义任何想要的速度模型(动画完成度 ÷ 时间完成度)。使用一个 Path 对象来绘制出想要的曲线(y 为动画完成度,x 为时间完成度)。 |
FastOutLinearInInterpolator | 持续加速(贝塞尔曲线,初始加速更快,肉眼并不明显)。 |
FastOutSlowInInterpolator | 先加速再减速(贝塞尔曲线,加速减速更快)。 |
LinearOutSlowInInterpolator | 持续减速(初始速度更快)。 |
三、属性动画PeopertyAnimation
3.1 ViewPropertyAnimator
通过 view.animate() 返回一个 ViewPropertyAnimator 对象并自动执行,局限性在于只能调用以下方法设置属性动画。
public ViewPropertyAnimator animate() |
3.1.1 动画模式
- 这些方法调用就会执行动画,在播放中途再次调用会先停留在原处,等进度赶上了再继续播放。当动画播放完毕后,不带by的方法再次调用不会执行,任何时候调用 start( ) 都无效果,调用 cancel() 会打断动画并会停留在原处,再次这些方法等进度赶上了再继续播放。
- 默认动画时长0.3s,通过 setDuration() 自定义。
- 默认速度模型开始加速结束减速(AccelerateDecelerateInterpolator),通过 setInterpolator() 自定义。
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.2 ObjectAnimator
ofFloat(Object target, String propertyName, float... values) 通过 ObjectAnimator.ofXXX() 创建对象,XXX具体选什么类型根据该属性设置方法的参数类型决定。target是目标View,propertyName是View的哪个属性(不是找同名变量修改值,是拼接出setter方法并调用,找不到IDE会提示。若是自定义View该属性需要提供setter方法,并在最后一行调用 invalidate() 触发重绘),values是目标值(填一个就是目标值,填两个就是起始值和目标值,填多个就是增加中间转接点值。若是自定义View,只填一个值的情况就需要该属性提供getter方法,会获取当前值当作起始值)。调用 start() 才会执行动画。 |
class MyView2 : View {var progress = 0Fset(value) {field = valueinvalidate() //重写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 动画监听
设置监听 | public void addListener(AnimatorListener listener) 重写onAnimationStart动画开始、onAnimationEnd动画结束、onAnimationCancel动画取消(对应调用了cancel时)、onAnimationRepeat动画重复(对应通过repeat播放时)。 |
更新监听 | 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 }
}
四、切换界面动画 Transition
五、补间动画 ViewAnimation(Tween)
5.1 动画模式
透明度 | AlphaAnimation(float fromAlpha, float toAlpha) fromAlpha:起始透明度。 toAlpha:结束透明度,透明度的范围为0-1。 |
缩放 | ScaleAnimation(float fromX, float toX, float fromY, float toY, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue) fromXScale/fromYScale:沿着X轴/Y轴缩放的起始比例。 toXScale/toYScale:沿着X轴/Y轴缩放的结束比例。 pivotX/pivotY:缩放的中轴点X/Y坐标,即距离自身左边缘的位置,比如50%就是以图像的中心为中轴点。 |
移动 | TranslateAnimation(int fromXType, float fromXValue, int toXType, float toXValue, int fromYType, float fromYValue, int toYType, float toYValue) fromXDelta/fromYDelta:动画起始位置的X/Y坐标。 toXDelta/toYDelta:动画结束位置的X/Y坐标。 |
旋转 | RotateAnimation(float fromDegrees, float toDegrees, int pivotXType, float pivotXValue, int pivotYType, float pivotYValue) fromDegrees/toDegrees:旋转的起始/结束角度。 |
动画集合 | 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) 传入要播放的动画。 |
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)
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()