View 动画原理与属性动画
从 Animation 到 PropertyAnimator 完全指南
目录
- 动画类型概述
- View Animation
- 属性动画 Property Animation
- Interpolator 插值器
- 自定义动画
- 动画组合与监听
1. 动画类型概述
flowchart TB
subgraph Old["View Animation(旧)"]
Tween["Tween Animation"] --> Scale["ScaleAnimation"]
Tween --> Rotate["RotateAnimation"]
Tween --> Translate["TranslateAnimation"]
Tween --> Alpha["AlphaAnimation"]
Old --> Frame["Frame Animation"]
end
subgraph New["Property Animation(新)"]
New --> Value["ValueAnimator"]
New --> Object["ObjectAnimator"]
New --> Set["AnimatorSet"]
end
subgraph Drawable["Drawable Animation"]
Drawable --> AnimationDrawable["AnimationDrawable"]
end
2. View Animation
基本用法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
<?xml version="1.0" encoding="utf-8"?> <scale xmlns:android="http://schemas.android.com/apk/res/android" android:duration="300" android:fromXScale="1.0" android:toXScale="1.2" android:fromYScale="1.0" android:toYScale="1.2" android:pivotX="50%" android:pivotY="50%" android:fillAfter="true" />
val animation = AnimationUtils.loadAnimation(this, R.anim.scale) view.startAnimation(animation)
animation.setAnimationListener(object : Animation.AnimationListener { override fun onAnimationStart(animation: Animation?) {} override fun onAnimationEnd(animation: Animation?) {} override fun onAnimationRepeat(animation: Animation?) {} })
|
View Animation 缺点
1 2 3 4 5 6 7
| view.startAnimation(TranslateAnimation(0f, 100f, 0f, 0f))
view.clearAnimation()
|
3. 属性动画 Property Animation
ValueAnimator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| val animator = ValueAnimator.ofInt(0, 100) animator.duration = 500 animator.addUpdateListener { animation -> val value = animation.animatedValue as Int view.layoutParams.width = value view.requestLayout() } animator.start()
val animator = ValueAnimator.ofFloat(0f, 1f) animator.duration = 300 animator.addUpdateListener { animation -> val value = animation.animatedValue as Float view.alpha = value } animator.start()
val animator = ValueAnimator.ofObject( TypeEvaluator { fraction, startValue, endValue -> val color = lerp(startValue as Int, endValue as Int, fraction) color }, Color.RED, Color.BLUE )
|
ObjectAnimator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| ObjectAnimator.ofFloat(view, "translationX", 0f, 100f).start() ObjectAnimator.ofFloat(view, "translationY", 0f, 100f).start() ObjectAnimator.ofFloat(view, "scaleX", 1f, 1.2f).start() ObjectAnimator.ofFloat(view, "rotation", 0f, 360f).start() ObjectAnimator.ofFloat(view, "alpha", 1f, 0f).start()
ObjectAnimator.ofFloat(view, "scaleX", 1f, 1.5f, 1f).start()
|
自定义属性动画
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class CircleView(context: Context) : View(context) { var sweepAngle: Float = 0f set(value) { field = value invalidate() } override fun onDraw(canvas: Canvas) { canvas.drawArc(rectF, -90f, sweepAngle, true, paint) } }
ObjectAnimator.ofInt(circleView, "sweepAngle", 0, 360).apply { duration = 1000 start() }
|
4. Interpolator 插值器
内置插值器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| AccelerateInterpolator() AccelerateDecelerateInterpolator()
DecelerateInterpolator()
BounceInterpolator()
OvershootInterpolator()
Repeatable (与 Reverse 组合)
LinearInterpolator()
|
插值器对比
flowchart TB
Interpolator["插值器对比"] --> Linear["Linear:匀速推进"]
Interpolator --> Accelerate["Accelerate:前慢后快"]
Interpolator --> Bounce["Bounce:中途弹跳"]
Interpolator --> Overshoot["Overshoot:超过终点再回弹"]
自定义插值器
1 2 3 4 5 6 7 8 9
| class CustomInterpolator : Interpolator { override fun getInterpolation(input: Float): Float { return 1 - (1 - input) * (1 - input) } }
|
5. 自定义动画
自定义 ValueAnimator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class CircleRevealAnimator(private val view: View) { private var animator: ValueAnimator? = null fun start() { animator = ValueAnimator.ofInt(view.width, 0).apply { duration = 300 interpolator = DecelerateInterpolator() addUpdateListener { animation -> val value = animation.animatedValue as Int view.layoutParams.width = value view.requestLayout() } } animator?.start() } fun cancel() { animator?.cancel() } }
|
自定义 TypeEvaluator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| val colorAnimator = ValueAnimator.ofObject( ArgbEvaluator(), Color.RED, Color.BLUE, Color.GREEN ).apply { duration = 2000 addUpdateListener { animation -> val color = animation.animatedValue as Int view.setBackgroundColor(color) } } colorAnimator.start()
val pathEvaluator = object : TypeEvaluator<PointF> { private val path = Path() override fun evaluate(fraction: Float, startValue: PointF, endValue: PointF): PointF { val x = startValue.x + (endValue.x - startValue.x) * fraction val y = startValue.y + (endValue.y - startValue.y) * fraction return PointF(x, y) } }
|
自定义 ObjectAnimator
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| var progress: Float = 0f private set
fun setProgress(value: Float) { progress = value invalidate() }
ObjectAnimator.ofFloat(view, "progress", 0f, 100f).apply { duration = 1000 start() }
|
6. 动画组合与监听
AnimatorSet
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| val scaleX = ObjectAnimator.ofFloat(view, "scaleX", 1f, 1.5f).apply { duration = 300 } val scaleY = ObjectAnimator.ofFloat(view, "scaleY", 1f, 1.5f).apply { duration = 300 } val alpha = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f).apply { duration = 300 }
AnimatorSet().apply { playTogether(scaleX, scaleY, alpha) start() }
AnimatorSet().apply { playSequentially(scaleX, alpha) start() }
AnimatorSet().apply { play(scaleX).with(scaleY) play(alpha).after(scaleX) start() }
|
PropertyValuesHolder
1 2 3 4 5 6 7 8 9
| val holder1 = PropertyValuesHolder.ofFloat("scaleX", 1f, 1.5f) val holder2 = PropertyValuesHolder.ofFloat("scaleY", 1f, 1.5f) val holder3 = PropertyValuesHolder.ofFloat("alpha", 1f, 0.5f)
ObjectAnimator.ofPropertyValuesHolder(view, holder1, holder2, holder3).apply { duration = 300 start() }
|
动画监听
1 2 3 4 5 6 7 8 9 10 11 12 13
| animator.addListener(object : Animator.AnimatorListener { override fun onAnimationStart(animation: Animator) {} override fun onAnimationEnd(animation: Animator) {} override fun onAnimationCancel(animation: Animator) {} override fun onAnimationRepeat(animation: Animator) {} })
animator.addUpdateListener { animation -> val value = animation.animatedValue }
|
面试常问
| 问题 |
答案 |
| View Animation vs 属性动画? |
View Animation 只改变显示,属性动画改变实际属性 |
| 动画为什么卡顿? |
16ms 内未完成,或在主线程做耗时操作 |
| 如何停止动画? |
animator.cancel() 或 view.clearAnimation() |
| Interpolator 作用? |
控制动画速率变化 |
总结
flowchart TB
AnimCore["Android 动画核心"] --> A1["View Animation:简单但有限制"]
AnimCore --> A2["Property Animation:改变实际属性,推荐"]
AnimCore --> A3["Interpolator:控制速率变化"]
AnimCore --> A4["AnimatorSet:组合复杂动画"]
相关文章: