Preface
The object of View animation is View, which supports 4 kinds of animation effects, which are translation animation, zoom animation, rotation animation and transparency animation, corresponding to the four subcategories of Animation: TranslateAnimation, ScaleAnimation, RotateAnimation and AlphaAnimation.
Panning
private fun translateAnimEx(btn: Button){
btn.text="平移动画"
// xml
val transAnimation = AnimationUtils.loadAnimation(this, R.anim.anim_translate_ex)
transAnimation.duration = 3000
btn.startAnimation(transAnimation)
// 代码
val transAnimation=TranslateAnimation(0f,180f,0f,180f)
transAnimation.duration = 3000
btn.startAnimation(transAnimation)
}
anim_translate_ex.xml文件
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="180"
android:toYDelta="180" />
effect:
Zoom animation
private fun scaleAnimEx(btn: Button){
btn.text="缩放动画"
// xml
val scaleAnimation = AnimationUtils.loadAnimation(this, R.anim.anim_scale_ex)
scaleAnimation.duration = 3000
btn.startAnimation(scaleAnimation)
// 代码
val scaleAnimation=ScaleAnimation(0f,120f,0f,120f,
50f, 50f)
scaleAnimation.duration = 3000
btn.startAnimation(scaleAnimation)
}
anim_scale_ex.xml
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXScale="0"
android:toXScale="20"
android:fromYScale="0"
android:toYScale="20"
android:pivotX="50"
android:pivotY="50"/>
effect:
Rotate animation
private fun rotateAnimEx(btn: Button){
btn.text="旋转动画"
// xml
val rotateAnimation = AnimationUtils.loadAnimation(this, R.anim.anim_rotate_ex)
rotateAnimation.duration = 3000
btn.startAnimation(rotateAnimation)
// 代码
val rotateAnimation=RotateAnimation(0f,360f,100f,100f)
rotateAnimation.duration = 3000
btn.startAnimation(rotateAnimation)
}
anim_rotate_ex.xml
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="0"
android:pivotX="100"
android:pivotY="100"
android:toDegrees="360" />
effect
Transparency animation
private fun alphaAnimEx(btn: Button){
btn.text="透明动画"
// xml
val alphaAnimation = AnimationUtils.loadAnimation(this, R.anim.anim_alpha_ex)
alphaAnimation.duration=3000
btn.startAnimation(alphaAnimation)
// 代码
val alphaAnimation = AlphaAnimation(0f, 1f)
alphaAnimation.duration = 3000
btn.startAnimation(alphaAnimation)
}
anim_alpha_ex.xml
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:fromAlpha="0"
android:toAlpha="1" />
effect
Animation collection
private fun setAnimEx(btn: Button){
// xml
val setAnimation = AnimationUtils.loadAnimation(this, R.anim.animation_set)
setAnimation.duration = 3000
btn.startAnimation(setAnimation)
// 代码
val rotateAnimation=RotateAnimation(0f,360f)
val transAnimation=TranslateAnimation(0f,180f,0f,180f)
val setAnimation=AnimationSet(false)
setAnimation.addAnimation(rotateAnimation)
setAnimation.addAnimation(transAnimation)
setAnimation.duration = 350
setAnimation.fillAfter=true
setAnimation.interpolator=LinearInterpolator()
setAnimation.zAdjustment=AnimationSet.ZORDER_NORMAL
btn.startAnimation(setAnimation)
}
animation_set.xml
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:fillAfter="true"
android:interpolator="@android:anim/linear_interpolator"
android:duration="350"
android:zAdjustment="normal">
<translate
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="100"
android:toYDelta="100" />
<rotate
android:duration="100"
android:fromDegrees="0"
android:toDegrees="360" />
</set>
Animation xml related attributes
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
//动画持续的时间
android:duration="{int}"
//动画结束以后View是否停留在结束位置,true表示View停留在结束位置,false则不停留
android:fillAfter="{true|false}"
//动画结束以后View是否停留在开始位置,true表示View停留在结束位置,false则不停留
android:fillBefore="{true|false}"
// 表示集合中的动画是否和集合共享同一个插值器
android:shareInterpolator="{true|false}"
// 重复模式
android:repeatMode="{restart|reverse}"
// 延时开始动画
android:startOffset="{int}"
// 设置插值器,
android:interpolator="@{package:}anim/interpolator_resource">
<rotate
//旋转开始的角度
android:fromDegrees="float"
//旋转的**轴点**的x坐标
android:pivotX="float"
// 旋转的**轴点**的y坐标
android:pivotY="float"
// 旋转结束的角度
android:toDegrees="float" />
<alpha
//表示透明度的起始值
android:fromAlpha="float"
//表示透明度的结束值
android:toAlpha="float" />
<scale
//水平方向缩放的起始值
android:fromXScale="float"
//竖直方向缩放的起始值
android:fromYScale="float"
//旋转的**轴点**的x坐标
android:pivotX="float"
// 旋转的**轴点**的y坐标
android:pivotY="float"
//水平方向缩放的结束值
android:toXScale="float"
//竖直方向缩放的结束值
android:toYScale="float" />
<translate
//表示x的起始值
android:fromXDelta="float"
//表示y的起始值
android:fromYDelta="float"
//水平方向缩放的结束值
android:toXDelta="float"
// 表示y的结束值
android:toYDelta="float" />
</set>
Custom animation
You only need to inherit the abstract class of Animation, then rewrite its initialize and applyTransformation methods, do some initialization work in the initialize method, and perform the corresponding matrix transformation in applyTransformation. In many cases, you need to use Camera to simplify the process of matrix transformation.
Example: 3D rotation
// 自定义View 动画
private fun animatonView() {
val rotate3DAnimation = Rotate3DAnimation(0f, 360f, 30f, 180f, true, 6f)
rotate3DAnimation.interpolator = AccelerateDecelerateInterpolator()
rotate3DAnimation.fillAfter = true
rotate3DAnimation.duration = 3500
btn_anim_set.startAnimation(rotate3DAnimation)
}
class Rotate3DAnimation : Animation {
private var mFromDegree: Float
private var mToDegree: Float
private var mCenterX: Float
private var mCenterY: Float
private var mDepthZ: Float
private var mReverse: Boolean
private lateinit var mCamera: Camera
constructor(mFromDegree: Float, mToDegree: Float, mCenterX: Float,mCenterY: Float, mReverse: Boolean, mDepthZ: Float) : super() {
this.mFromDegree = mFromDegree
this.mCenterY = mCenterY
this.mCenterX = mCenterX
this.mToDegree = mToDegree
this.mReverse = mReverse
this.mDepthZ = mDepthZ
}
// 初始化
override fun initialize(width: Int, height: Int, parentWidth: Int, parentHeight: Int) {
super.initialize(width, height, parentWidth, parentHeight)
this.mCamera = Camera()
}
// 矩阵变化
override fun applyTransformation(interpolatedTime: Float, t: Transformation?) {
super.applyTransformation(interpolatedTime, t)
var fromDegree=mFromDegree
var degree=fromDegree+(mToDegree-mFromDegree)*interpolatedTime
var centerX=mCenterX
var centerY=mCenterY
val camera=mCamera
val matrix=t?.matrix
//将当前的摄像头位置保存下来,以便变换进行完成后恢复成原位
camera.save()
// camera.translate,这个方法接受3个参数,分别是x,y,z三个轴的偏移量,我们这里只将z轴进行了偏移
if (mReverse){
// z的偏移会越来越大。这就会形成这样一个效果,view从近到远
camera.translate(0f,0f,mDepthZ*interpolatedTime)
}else{
// z的偏移会越来越小。这就会形成这样一个效果,我们的View从一个很远的地方向我们移过来,越来越近,
// 最终移到了我们的窗口上面
camera.translate(0f,0f,mDepthZ*(1f-interpolatedTime))
}
// View加上旋转效果,在移动的过程中,视图还会移Y轴为中心进行旋转
camera.rotateY(degree)
// 将我们刚才定义的一系列变换应用到变换矩阵上面,调用完这句之后,我们就可以将camera的位置恢复了,以便下一次再使用
camera.getMatrix(matrix)
// camera位置恢复
camera.restore()
// 以View的中心点为旋转中心,如果不加这两句,就是以(0,0)点为旋转中心
matrix?.preTranslate(-centerX,-centerY)
matrix?.postTranslate(centerX,centerY)
}
}
effect:
VIew animation principle
Each time a view is drawn, the drawChild function in the ViewGroup where the View is located obtains the Transformation value of the View's Animation, and then calls canvas.contact(transformToApply.getMatrix()) to complete the animation frame through matrix operations. If the animation is not completed, continue to call the invalidate() function to start the next drawing to drive the animation, so as to complete the drawing of the entire animation.