安卓中的三种动画:
一、Drawable Animation也就是所谓的帧动画,Frame动画。指通过指定每一帧的图片和播放时间,有序的进行播放而形成动画效果。
二、View Animation视图动画,也就是所谓补间动画,Tween动画。指通过指定View的初始状态、变化时间、方式,通过一系列的算法去进行图形变换,从而形成动画效果,主要有Alpha、Scale、Translate、Rotate四种效果。注意:只是在视图层实现了动画效果,并没有真正改变View的属性。三、Property Animation属性动画,通过不断的改变View的属性,不断的重绘而形成动画效果。相比于视图动画,View的属性是真正改变了。注意:Android 3.0(API 11)以上才支持。
Tip:view动画不改变view的真实位置,就是肉眼看上去,view位置发生了变化,但是它的点击区域还是在原来的位置。
https://segmentfault.com/a/1190000011933148
属性动画
1.ViewPropertyAnimator
View.animate()方法调用后返回一个ViewPropertyAnimator对象
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
view.animate().translationX(100f)
.translationY(100f)
.scaleX(0.5f)
.scaleY(0.5f)
.rotation(270f)
.setDuration(1000)
.setStartDelay(1000)
}
}
2.ObjectAnimator
使⽤ ObjectAnimator.ofXxx() 来创建对象,以及使⽤ObjectAnimator.start() 来主动启动动画。它的优势在于,可以为⾃定义属性设置动画。
CircleView
class CircleView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
var radius = 50f
set(value) {
field = value
invalidate()
}
init {
paint.color = Color.parseColor("#00796B")
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
canvas.drawCircle(width / 2f, height / 2f, radius, paint)
}
}
MainActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val anim = ObjectAnimator.ofFloat(view,"radius",150f)
anim.startDelay = 1000
anim.start()
}
}
2.1.Interpolator插值器
⽤于设置时间完成度到动画完成度的计算公式,直⽩地说即设置动画的速度曲线,通过 setInterpolator(Interpolator) ⽅法来设置。
常⽤的有 AccelerateDecelerateInterpolator(先加速再减速)、AccelerateInterpolator(一直加速)、DecelerateInterpolator(一直减速)、LinearInterpolator (匀速)
val anim = ObjectAnimator.ofFloat(view,"translationX",500f)
anim.startDelay = 1000
anim.duration = 1500
anim.interpolator = AccelerateDecelerateInterpolator()
anim.start()
2.2.AnimatorSet
将多个 Animator 合并在⼀起使⽤,先后顺序或并列顺序都可以
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(animator1, animator2);
animatorSet.start();
2.3PropertyValuesHolder
⽤于设置更加详细的动画
1.例如多个属性应⽤于同⼀个对象(类似于AnimatorSet,同时做):
val anim = PropertyValuesHolder.ofFloat("radius",150f)
val anim2 = PropertyValuesHolder.ofFloat("translationX",300f)
val animator = ofPropertyValuesHolder(view, anim,anim2)
animator.startDelay = 1000
animator.start()
2.配合使⽤ Keyframe ,所有的关键帧对⼀个属性分多个段,会根据关键帧的fraction(进度百分比)和value来决定动画效果
val length = 500f
val keyframe1 = Keyframe.ofFloat(0f,0f)
val keyframe2 = Keyframe.ofFloat(0.2f,0.3f * length)
val keyframe3 = Keyframe.ofFloat(0.8f,0.5f * length)
val keyframe4 = Keyframe.ofFloat(1f,length)
val keyframeHolder = PropertyValuesHolder.ofKeyframe("translationX",keyframe1,keyframe2,keyframe3,keyframe4)
val animator = ofPropertyValuesHolder(view,keyframeHolder)
animator.startDelay = 1000
animator.duration = 3000
animator.start()
3.TypeEvaluator
⽤于设置动画完成度到属性具体值的计算公式。默认的 ofInt() ofFloat() 已经有了⾃带的 IntEvaluator FloatEvaluator ,但有的时候需要⾃⼰设置Evaluator。例如,对于颜⾊,需要为 int 类型的颜⾊设置 ArgbEvaluator,⽽不是让它们使⽤ IntEvaluator
eg:用evaluator实现字符串的变化
ProvinceView
private val provinces = listOf("北京市",
"天津市",
"上海市",
"重庆市",
"河北省",
"山西省",
"辽宁省",
"吉林省",
"黑龙江省",
"江苏省",
"浙江省",
"安徽省",
"福建省",
"江西省",
"山东省",
"河南省",
"湖北省",
"湖南省",
"广东省",
"海南省",
"四川省",
"贵州省",
"云南省",
"陕西省",
"甘肃省",
"青海省",
"台湾省",
"内蒙古自治区",
"广西壮族自治区",
"西藏自治区",
"宁夏回族自治区",
"新疆维吾尔自治区",
"香港特别行政区",
"澳门特别行政区")
class ProvinceView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
textSize = 80f
textAlign = Paint.Align.CENTER
}
var province = "北京市"
set(value) {
field = value
invalidate()
val drawable = ColorDrawable()
drawable.toBitmap().toDrawable(resources)
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
canvas.drawText(province, width / 2f, height / 2f, paint)
}
}
class ProvinceEvaluator: TypeEvaluator<String>{
override fun evaluate(fraction: Float, startValue: String?, endValue: String?): String {
val startIndex = provinces.indexOf(startValue)
val endIndex = provinces.indexOf(endValue)
val currentIndex = startIndex + ((endIndex - startIndex) * fraction).toInt()
return provinces[currentIndex]
}
}
MainActivity
val anim = ObjectAnimator.ofObject(view,"province",ProvinceEvaluator(),"澳门特别行政区")
anim.startDelay = 1000
anim.duration = 10000
anim.interpolator = AccelerateDecelerateInterpolator()
anim.start()
4.Listeners
和 View 的点击、⻓按监听器⼀样,Animator 也可以使⽤ setXxxListener()
addXxxListener() 来设置监听器。
5.ValueAnimator
是最基本的 Animator,它不和具体的某个对象联动,⽽是直接对两个数值进⾏渐变计算。
硬件加速
- 使⽤ CPU 绘制到 Bitmap,然后把 Bitmap 贴到屏幕,就是软件绘制;
- 使⽤ CPU 把绘制内容(onDraw())转换成 GPU 操作,交给 GPU,由 GPU 负责真正的绘制,
就叫硬件绘制; - 使⽤ GPU 绘制就叫做硬件加速
1.原理?
- GPU 分摊了⼯作
- GPU 绘制简单图形(例如⽅形、圆形、直线)在硬件设计上具有先天优势,会
更快 - 流程得到优化(重绘流程涉及的内容更少)
2.缺点?
兼容性
3.离屏缓冲
是什么?
内存中抽出一个单独的⼀个绘制 View(或 View 的⼀部分)的区域,然后贴到屏幕
3.1 setLayerType() 和 saveLayer()
- saveLayer() 是针对 Canvas 的,所以在 onDraw() ⾥可以使⽤ saveLayer()来圈出具体哪部分绘制要⽤离屏缓冲(太重了,所以最好不使用)
- setLayerType() 是对整个 View,不能针对 onDraw() ⾥⾯的某⼀具体过程
init {
setLayerType(LAYER_TYPE_HARDWARE,null)
setLayerType(LAYER_TYPE_SOFTWARE,null)
setLayerType(LAYER_TYPE_NONE,null)
}
LAYER_TYPE_HARDWARE表示开启View的离屏缓冲并使用硬件绘制
LAYER_TYPE_SOFTWARE表示开启View的离屏缓冲并使用软件绘制
(这个⽅法常⽤来关闭硬件加速,但它的定位和定义都不只是⼀个「硬件加速开关」。它的作⽤是为绘制设置⼀个离屏缓冲,让后⾯的绘制都单独写在这个离屏缓冲内。如果参数填写 LAYER_TYPE_SOFTWARE ,会把离屏缓冲设置为⼀个 Bitmap ,即使⽤软件绘制来进⾏缓冲,这样就导致在设置离屏缓冲的同时,将硬件加速关闭了。)
LAYER_TYPE_NONE表示关闭View的离屏缓冲
3.2 对于系统自带的属性动画
可使用如下代码配合LAYER_TYPE_HARDWARE、LAYER_TYPE_NONE提高动画性能:
view.animate()
.translationY(500f)
.withLayer()
开启离屏缓冲,GPU会自动渲染改变后的位置,而不会重绘