在引入屬性動畫
以前,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…