在引入属性动画
以前,Android已经有了Tween animation(补间动画)
。引入新的Animator的缘由是由于补间动画有不少局限性。 补间动画的分类:java
AlphaAnimation
ScaleAnimation
TranslateAnimation
RotateAnimation
AnimationSet
补间动画的局限性:android
为了补充和解决上述补间动画的不足,因此在Android3的时候引入了ValueAnimator
和ObjectAnimator
。git
序号 | 类名 | 说明 |
---|---|---|
1 | Animator | 全部 Animator 的父类,主要用于定义通用的接口 |
2 | AnimatorSet | 多个属性动画组合 |
3 | ValueAnimator | 主要用于根据起始值和终止值产生动画,只负责产生在起始值和终止值之间的值 |
4 | ObjectAnimator | 主要用于根据起始值和终止值产生动画,并将动画产生的值设置在目标对象上 |
5 | TimeAnimator | 提供了一个简单的回调机制,经过 TimeAnimator.TimeListener,在动画的每一帧处通知你。(本文不会介绍) |
继承结构:github
跟补间动画同样,可使用Xml和Code的方式建立动画。canvas
在animation文件夹中建立xml动画文件。(若是没有animation文件夹,须要手动建立)ide
<objectAnimator android:duration="int" android:interpolator="@[package:]anim/interpolator_resource" android:propertyName="string" android:valueType=["intType" | "floatType"] android:valueFrom="float | int | color" android:valueTo="float | int | color" android:startOffset="int" android:repeatCount="int" android:repeatMode=["repeat" | "reverse"] />
复制代码
属性 | 含义 | 取值范围 |
---|---|---|
duration | 动画执行时间 | 整型,须要大于0。 |
interpolator | 差值器,改变更画或者数值变化的速率 | 安卓自带,自定义 |
propertyName | 动画目标对象要改变的属性 | 字符串,填入属性名称 |
valueType | 值类型 | 整点型,浮点型。当属性动画值的类型为颜色值时能够省略 |
valueFrom | 动画值的起始值 | 浮点数,整型数或者颜色值。当为颜色值时,必须符合颜色的定义方式(# + 六位十六进制数) |
valueTo | 动画值的结束值 | 浮点数,整型数或者颜色值。当为颜色值时,必须符合颜色的定义方式(# + 六位十六进制数) |
startOffset | 动画开始偏移时间 | 整型数,默认为 0。当为负数时,效果和默认值同样 |
repeatCount | 动画重复的次数 | 整型数字,默认为 0。当为负数时,表示无限循环 |
repeatMode | 下一次动画执行的方式 | 默认:从新开始播放。还有倒播 |
//1. 在animation文件夹中建立xml文件
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:propertyName="rotation"
android:valueType="floatType"
android:valueFrom="0"
android:valueTo="360"
android:startOffset="0"
android:repeatCount="infinite"
android:repeatMode="reverse"
/>
//2. 在代码中导入动画xml
val objectAnimator = AnimatorInflater.loadAnimator(this, R.animator.object_animator) as ObjectAnimator
objectAnimator.setTarget(target)
objectAnimator.start()
复制代码
代码的建立方式在下面介绍。post
ValueAnimator
正如其名字,它是关于数字的计算动画。它不会与View直接交互,而是经过ValueAnimator#addUpdateListener
来设置动画效果。好比在TextView上显示从0到50时,就能够用ValueAnimator
。测试
在代码中建立ValueAnimator
。动画
// 建立Animator,同时传入取值范围
val animator = ValueAnimator.ofFloat(0F, 5000F)
// 设置差值器, 这里选择的是线性差值器(默认)
animator.interpolator = LinearInterpolator()
// 设置动画执行时间
animator.setDuration(2000)
复制代码
在ValueAnimator中有数值变化时,会调用onAnimationUpdate
接口。因此咱们须要实现这个Listener。ui
animator.addUpdateListener {
// 在TextView中更新text
binding.textView.text = ((it.animatedValue as Float).toInt() / 100).toString()
// 把值传入自定义贝塞尔View,是其产生动画效果
binding.bezierView.setValue(it.animatedValue as Float)
}
复制代码
自定义贝塞尔View的源码以下。 关于贝塞尔曲线,能够参考个人另外一篇文章。
class BezierView : View {
private var path: Path = Path()
private lateinit var paint: Paint = Paint()
private var h: Int = 0
private var w: Int = 0
private var controlPoint1: PointF = PointF()
private var controlPoint2: PointF = PointF()
constructor(context: Context) : this(context, null)
constructor(context: Context, attributeSet: AttributeSet?) : super(context, attributeSet)
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
// 设置当前view的高和宽
this.h = h
this.w = w
controlPoint1 = PointF(this.w.toFloat() / 4, 0F)
controlPoint2 = PointF(this.w.toFloat() / 4 * 3, this.h.toFloat())
}
fun setValue(degree: Float) {
val controlY = degree / 5000 * h
controlPoint1 = PointF(this.w.toFloat() / 4, controlY)
controlPoint2 = PointF(this.w.toFloat() / 4 * 3, this.h.toFloat() - controlY)
invalidate()
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
// 重置path, 为的是防止重复绘制贝塞尔曲线,使画布上残留多条曲线
path.reset()
// 配置画笔paint
paint.color = context.getColor(R.color.colorAccent)
paint.strokeWidth = 2F
paint.style = Paint.Style.STROKE
// 设置左右两个基准点
val pointLeft = PointF(0F, h / 2.toFloat())
val pointRight = PointF(w.toFloat(), h / 2.toFloat())
// 绘制左右基准点
canvas?.drawPoint(pointLeft.x, pointLeft.y, paint)
canvas?.drawPoint(pointRight.x, pointRight.y, paint)
paint.color = context.getColor(R.color.colorPrimaryDark)
// 为了绘制贝塞尔曲线,须要移动到其中一个基准点
path.moveTo(pointLeft.x, pointLeft.y)
// 根据基准点和控制点,绘制贝塞尔曲线
path.cubicTo(
controlPoint1.x,
controlPoint1.y,
controlPoint2.x,
controlPoint2.y,
pointRight.x,
pointRight.y
)
// 在画布上画path
canvas?.drawPath(path, paint)
}
}
复制代码
最后须要在合适的节点开始播放动画。
// 播放动画
animator.start()
// 动画暂定
animator.pause()
// 播放结束
animator.end()
复制代码
跟ValueAnimator
同样的方式建立ObjectAnimator
。
// 建立动画,
val objectAnimator = ObjectAnimator.ofFloat(binding.imageView, "rotation", 0F, 360F, 0F)
// 设置动画执行时间
objectAnimator.setDuration(2000)
// 开始播放
objectAnimator.start()
复制代码
建立动画时的第一个传参是被动画对象View,第二个是properyName
,第三个是变长参数的起始数值。
其中propertyName
的类型一共有如下几种:
名称 | 做用 |
---|---|
alpha | 透明化 |
rotation | 旋转 |
rotationX | 以X轴旋转 |
rotationY | 以Y轴旋转 |
translationX | 以X轴平移 |
translationY | 以Y轴平移 |
scaleX | 以X轴拉伸 |
scaleY | 以Y轴拉伸 |
属性动画的监听器一共有三种。
AnimatorListener
AnimatorPauseListener
AnimatorUpdateListener
AnimatorListener
的监听器主要监听的是属性动画的开始,结束,取消,重复。
public static interface AnimatorListener{
void onAnimationStart(Animator animation, boolean isReverse) {}
void onAnimationEnd(Animator animation, boolean isReverse) {}
void onAnimationCancel(Animator animation, boolean isReverse) {}
void onAnimationRepeat(Animator animation, boolean isReverse) {}
}
复制代码
AnimatorPauseListener
的监听器主要监听的是属性动画的暂停,恢复状态。
public static interface AnimatorPauseListener {
void onAnimationPause(Animator animation);
void onAnimationResume(Animator animation);
}
复制代码
AnimatorUpdateListener
的监听器主要监听的是属性动画中值得变化。
public static interface AnimatorUpdateListener {
void onAnimationUpdate(ValueAnimator animation);
}
复制代码
属性动画的Interpolator
和补间动画的的是同样的。 插值器一共有一下几种:
名称 | 做用 |
---|---|
AccelerateDecelerateInterpolator | 先加速,后减速 |
AccelerateInterpolator | 一直加速 |
AnticipateInterpolator | 迂回,加速 |
OvershootInterpolator | 加速超出,返回终点 |
AnticipateOvershootInterpolator | 迂回,加速超出,返回终点 |
BounceInterpolator | 弹簧效果 |
CycleInterpolator | 正弦曲线 |
DecelerateInterpolator | 一直减速 |
LinearInterpolator | 线性速度 |
若是上面的插值器不符合要求能够自定义一个新的插值器。 自定义插值器时须要继承BaseInterpolator
。 重写public float getInterpolation(float input)
。
线性插值器是以下的代码,能够做为参考。
public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
public LinearInterpolator() {
}
public LinearInterpolator(Context context, AttributeSet attrs) {
}
public float getInterpolation(float input) {
return input;
}
/** @hide */
@Override
public long createNativeInterpolator() {
return NativeInterpolatorFactoryHelper.createLinearInterpolator();
}
}
复制代码
估值器是用于计算ValueAnimator
中的数值变化。ValueAnimator
的默认的估值器是线性的。 若是想要自定义估值器须要继承TypeEvaluator
,以及重写public T evaluate(float fraction, T startValue, T endValue);
。
示例以下:
class CustomTypeEvaluator : TypeEvaluator<Float> {
override fun evaluate(fraction: Float, startValue: Float?, endValue: Float?): Float {
return fraction * abs(endValue ?: 0F - startValue!!)
}
}
复制代码
本文的示例: github.com/HyejeanMOON…
其余教程:
Google的MergeAdapter的使用: juejin.im/post/5e903f…
Paging在Android中的应用: juejin.im/post/5e75db…
Android UI测试之Espresso: juejin.im/post/5e6caa…
Android ConstraintLayout的易懂教程: juejin.im/post/5ea50a…
在RecyclerView中能够应对多个ViewType的库--Groupie: juejin.im/post/5e9059…