属性动画
属性动画 ViewPropertyAnimator
//1. 属性动画ViewPropertyAnimator
view.animate()
.translationX(200.dp)//横向移动
.translationY(100.dp)//纵向移动
.alpha(0.5f)//透明度
.scaleX(2f)//横向放大
.scaleY(2f)//纵向放大
.rotation(90f)//旋转90度
.setStartDelay(1000)//延迟一秒执行
属性动画 ObjectAnimator
使用方式:
- 如果是自定义控件,需要添加 setter / getter 方法;
- 用 ObjectAnimator.ofXXX() 创建 ObjectAnimator 对象;
- 用 start() 方法执行动画。
-
圆放大效果 ofFloat
val animator = ObjectAnimator.ofFloat(circleView, "radius", 150.dp) animator.startDelay = 1000 animator.start() -
组合动画AnimatorSet
val bottomFlipAnimator = ObjectAnimator.ofFloat(cameraView, "bottomFlip", 60f) bottomFlipAnimator.startDelay = 1000 bottomFlipAnimator.duration = 1000 val flipRotationAnimator = ObjectAnimator.ofFloat(cameraView, "flipRotation", 270f) flipRotationAnimator.startDelay = 200 flipRotationAnimator.duration = 1000 val topFlipAnimator = ObjectAnimator.ofFloat(cameraView, "topFlip", -60f) topFlipAnimator.startDelay = 200 topFlipAnimator.duration = 1000 val animatorSet = AnimatorSet() animatorSet.playSequentially(bottomFlipAnimator,flipRotationAnimator,topFlipAnimator) animatorSet.start() -
PropertyValuesHolder
- 效果同上
val bottomFlipHolder = PropertyValuesHolder.ofFloat("bottomFlip", 60f) val flipRotationHolder = PropertyValuesHolder.ofFloat("flipRotation", 270f) val topFlipHolder = PropertyValuesHolder.ofFloat("topFlip", - 60f) val holderAnimator = ObjectAnimator.ofPropertyValuesHolder(cameraView, bottomFlipHolder, flipRotationHolder, topFlipHolder) holderAnimator.startDelay = 1000 holderAnimator.duration = 2000 holderAnimator.start() -
PropertyValuesHolder 配合Keyframe 细化动画
- 下面是一个用关键帧做的回弹动画
val length = 200.dp val keyframe1 = Keyframe.ofFloat(0f, 0f) val keyframe2 = Keyframe.ofFloat(0.2f, 1.5f * length) val keyframe3 = Keyframe.ofFloat(0.8f, 0.6f * length) val keyframe4 = Keyframe.ofFloat(1f, 1f * length) val keyframeHolder = PropertyValuesHolder.ofKeyframe("translationX", keyframe1, keyframe2, keyframe3, keyframe4) val animator = ObjectAnimator.ofPropertyValuesHolder(cameraView, keyframeHolder) animator.startDelay = 1000 animator.duration = 2000 animator.start() -
Interpolator 插值器
- Interpolator 其实就是速度设置器。你在参数里填入不同的 Interpolator ,动画就会以不同的速度模型来执行
val animator = ObjectAnimator.ofFloat(cameraView,"translationX", 360.dp) animator.interpolator = AccelerateDecelerateInterpolator()//先加速再减速 // animator.interpolator = AccelerateInterpolator()//一直加速 // animator.interpolator = LinearInterpolator()//匀速 animator.startDelay = 1000 animator.duration = 1000 animator.start() -
TypeEvaluator 估值器
- 圆点移动效果
val animator = ObjectAnimator.ofObject( pointView, "point", pointFEvaluator(), PointF(100.dp, 200.dp) ) animator.startDelay = 1000 animator.duration = 1000 animator.start() //自定义估值器 class pointFEvaluator:TypeEvaluator<PointF> { override fun evaluate(fraction: Float, startValue: PointF, endValue: PointF): PointF { val startX= startValue.x val endX = endValue.x val currentX = startX + (endX-startX)*fraction val startY= startValue.y val endY = endValue.y val currentY = startY + (endY-startY)*fraction return PointF(currentX,currentY) } }- 文字滚动效果,模拟城市地区滚动效果
//TypeEvaluator 文字滚动效果 val animator = ObjectAnimator.ofObject(proviceView,"province",ProvinceEvaluator(),"澳门特别行政区") animator.startDelay = 1000 animator.duration = 10000 animator.start()class ProvinceView(context: Context?, attrs: AttributeSet?) : View(context, attrs) { ... private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply { textSize = 40.dp textAlign = Paint.Align.CENTER } var province = "北京市" set(value) { field = value invalidate() } ... } -
Listeners 设置监听器
和 View 的点击、⻓按监听器一样,Animator 也可以使用 setXxxListener() addXxxListener() 来设置监听器。
- 给动画设置监听器,可以在关键时刻得到反馈,从而及时做出合适的操作,例如在动画的属性更新时同步更新其他数据,或者在动画结束后回收资源等。
- 设置监听器的方法, ViewPropertyAnimator 和 ObjectAnimator 略微不一样: ViewPropertyAnimator 用的是 setListener() 和 setUpdateListener() 方法,可以设置一个监听器,要移除监听器时通过 set[Update]Listener(null) 填 null 值来移除;而 ObjectAnimator 则是用 addListener() 和 addUpdateListener() 来添加一个或多个监听器,移除监听器则是通过 remove[Update]Listener() 来指定移除对象。
- 另外,由于 ObjectAnimator 支持使用 pause() 方法暂停,所以它还多了一个 addPauseListener() / removePauseListener() 的支持;而 ViewPropertyAnimator 则独有 withStartAction() 和 withEndAction() 方法,可以设置一次性的动画开始或结束的监听。
- ViewPropertyAnimator.setListener() / ObjectAnimator.addListener()
- onAnimationStart(Animator animation) 开始执行时
- onAnimationEnd(Animator animation) 动画结束时
- onAnimationCancel
- 当动画被通过 cancel() 方法取消时,这个方法被调用。
- 需要说明一下的是,就算动画被取消,onAnimationEnd() 也会被调用。所以当动画被取消时,如果设置了 AnimatorListener,那么 onAnimationCancel() 和 onAnimationEnd() 都会被调用。onAnimationCancel() 会先于 onAnimationEnd() 被调用。
- onAnimationRepeat(Animator animation)
- 当动画通过 setRepeatMode() / setRepeatCount() 或 repeat() 方法重复执行时,这个方法被调用。
- 由于 ViewPropertyAnimator 不支持重复,所以这个方法对 ViewPropertyAnimator 相当于无效。
- ViewPropertyAnimator.setUpdateListener() / ObjectAnimator.addUpdateListener()
- 和上面的两个方法一样,这两个方法虽然名称和可设置的监听器数量不一样,但本质其实都一样的,它们的参数都是 AnimatorUpdateListener。它只有一个回调方法:onAnimationUpdate(ValueAnimator animation)。
- ObjectAnimator.addPauseListener()
- ViewPropertyAnimator.withStartAction/EndAction()
- 这两个方法是 ViewPropertyAnimator 的独有方法。它们和 set/addListener() 中回调的 onAnimationStart() / onAnimationEnd() 相比起来的不同主要有两点:
- withStartAction() / withEndAction() 是一次性的,在动画执行结束后就自动弃掉了,就算之后再重用 ViewPropertyAnimator 来做别的动画,用它们设置的回调也不会再被调用。而 set/addListener() 所设置的 AnimatorListener 是持续有效的,当动画重复执行时,回调总会被调用。
- withEndAction() 设置的回调只有在动画正常结束时才会被调用,而在动画被取消时不会被执行。这点和 AnimatorListener.onAnimationEnd() 的行为是不一致的。
- 这两个方法是 ViewPropertyAnimator 的独有方法。它们和 set/addListener() 中回调的 onAnimationStart() / onAnimationEnd() 相比起来的不同主要有两点:
ValueAnimator
这是最基本的 Animator,它不和具体的某个对象联动,而是直接对两个数值进行渐 变计算。使用很少。
硬件加速
- 使用 CPU 绘制到 Bitmap,然后把 Bitmap 贴到屏幕,就是软件绘制;
- 使用 CPU 把绘制内容转换成 GPU 操作,交给 GPU,由 GPU 负责真正的绘制, 就叫硬件绘制;
- 使用 GPU 绘制就叫做硬件加速
如何加速
- GPU 分摊了工作
- GPU 绘制简单图形(例如方形、圆形、直线)在硬件设计上具有先天优势,会 更快
- 流程得到优化(重绘流程涉及的内容更少)
缺陷
兼容性。由于使用 GPU 的绘制(暂时)无法完成某些绘制,因此对于一些特定的 API,需要关闭硬件加速来转回到使用 CPU 进行绘制。
如图,官方文档上关于硬件加速无法绘制的api列表
离屏缓冲
- 离屏缓冲是什么:单独的一个绘制 View(或 View 的一部分)的区域
- setLayerType() 和 saveLayer()
- setLayerType() 是对整个 View,不能针对 onDraw() 里面的某一具体过程
- 这个方法常用来关闭硬件加速,但它的定位和定义都不只是一个「硬件 加速开关」。它的作用是为绘制设置一个离屏缓冲,让后面的绘制都单 独写在这个离屏缓冲内。如果参数填写 LAYER_TYPE_SOFTWARE ,会把离屏缓冲设置为一个 Bitmap ,即使用软件绘制来进行缓冲,这样 就导致在设置离屏缓冲的同时,将硬件加速关闭了。但需要知道,这个 方法被用来关闭硬件加速,只是因为 Android 并没有提供一个便捷的方 法在 View 级别简单地开关硬件加速而已。
- saveLayer() 是针对 Canvas 的,所以在 onDraw() 里可以使用 saveLayer() 来圈出具体哪部分绘制要用离屏缓冲
- 然而......最新的文档表示这个方法太重了,能不用就别用,尽量用 setLayerType() 代替
- setLayerType() 是对整个 View,不能针对 onDraw() 里面的某一具体过程