Android必备知识点之动画(Animation/Animator)

  • 逐帧动画【Frame Animation】,即顺序播放事先做好的图像,跟电影类似
  • 补间动画【Tween Animation】,即通过对场景里的对象不断做图像变换 ( 平移、缩放、旋转 ) 产生动画效果
  • 属性动画【Property Animation】,补间动画增强版,支持对对象执行动画
  • 过渡动画【Transition Animation】,实现Activity或View过渡动画效果

Animation 具体实现

可以理解为,基于Matrix(矩阵)的图形变化 矩阵 是一组排列成矩形的或者排列成行成列的数字或符号。 要计算矩阵的乘法,你需要用第一个矩阵行上的元素(或数字)乘以第二个矩阵中列上的元素,再计算它们的和。

1 确认矩阵是否可以相乘。只有第一个矩阵的列的个数等于第二个矩阵的行的个数,这样的两个矩阵才能相乘。 2 计算结果矩阵的行列数。画一个空白的矩阵,来代表矩阵乘法的结果。矩阵A和矩阵B相乘得到的矩阵,与矩阵A有相同的行数,与矩阵B有相同的列数。 3 计算第一个“点”。要计算矩阵中的第一个“点”,你需要用第一个矩阵第一行的第一个数乘以第二个矩阵第一列的第一个数,第一行的第二个数乘以第一列的第二个数,第一行的第三个数乘以第一列的第三个数,然后将这三个结果加到一起,得到第一个点。 例子: https://zh.wikihow.com/%E8%AE%A1%E7%AE%97%E7%9F%A9%E9%98%B5%E4%B9%98%E6%B3%95

缩放(Scale)

让我们实现把一个点 (x0, y0) 的 x 轴和 y 轴分别缩放 k1 和 k2 倍,我们会怎么做,很简单

alt

点 (x0, y0) 用矩阵表示是这样的

alt

小知识点: 最后一位:1,0的含义:(x, y, 1) -> 点 (x, y, 0) -> 向量

结果:

alt

可以看到,矩阵相乘得到了一个(k1x0, k2y0,1)的矩阵,上面说过,计算机中,这个矩阵就代表点 (k1x0, k2y0), 而这个点刚好就是我们要的缩放之后的点

代码表示:

val xy = FloatArray(x0, y0)
Matrix().apply {
    setScale(k1, k2)   
    mapPoints(xy)
}

平移(Translate)

val x = x0 + deltaX
val y = y0 + deltaY

alt 代码表示:

val xy = FloatArray(x0, y0)
Matrix().apply {
    setTranslate(k1, k2)   
    mapPoints(xy)
}

旋转(Rotate)

alt

假设一个点 A(x0, y0), 距离原点的距离为 r,与水平夹角为 α,现绕原点顺时针旋转 θ 度,旋转之后的点为 B(x, y)

alt

alt

alt

参考:https://cloud.tencent.com/developer/article/1915878

Animator 具体实现

alt

Animator,所有属性动画的父类,为开始、结束属性动画和添加动画监听器提供了支持。

AnimatorSet,属性动画的合集

ValueAnimator, 仅仅是对数值的属性动画,并不能表现在UI上

ObjectAnimator,对View的属性动画

ValueAnimator

//设置ValueAnimator,1-100的浮点数之间的动画渐变
val valueAnimator = ValueAnimator.ofFloat(1.0F, 100.0F).setDuration(1000)
//设置一个监听器
valueAnimator.addUpdateListener {
    val value = it.animatedValue as Float
    Log.e("TAG", "Value=$value")
}
valueAnimator.start()

//输出结果
07-23 15:46:00.944 13240-13240/top.littledavid.studyanimation E/TAG: Value=1.0
07-23 15:46:00.945 13240-13240/top.littledavid.studyanimation E/TAG: Value=1.0
07-23 15:46:00.978 13240-13240/top.littledavid.studyanimation E/TAG: Value=1.0705773
07-23 15:46:01.010 13240-13240/top.littledavid.studyanimation E/TAG: Value=1.609426
//............................................
07-23 15:46:01.431 13240-13240/top.littledavid.studyanimation E/TAG: Value=47.857613
07-23 15:46:01.450 13240-13240/top.littledavid.studyanimation E/TAG: Value=50.5
07-23 15:46:01.465 13240-13240/top.littledavid.studyanimation E/TAG: Value=53.142387
07-23 15:46:01.484 13240-13240/top.littledavid.studyanimation E/TAG: Value=55.6226
07-23 15:46:01.499 13240-13240/top.littledavid.studyanimation E/TAG: Value=58.243496
//...........................................
07-23 15:46:01.915 13240-13240/top.littledavid.studyanimation E/TAG: Value=99.73422
07-23 15:46:01.931 13240-13240/top.littledavid.studyanimation E/TAG: Value=99.92943
07-23 15:46:01.948 13240-13240/top.littledavid.studyanimation E/TAG: Value=100.0
-----------------------------------

可以看出:ValueAnimator是仅仅是一种对数值的动画

因为ValueAnimator不能作用于对象,仅仅是对数值做了一个动画,如果我们想将ValueAnimator作为动画的话,需要在ValueAnimator的动画监听中来手动地更新对象。

/**
建立一个简单的Person类,接线来我们将会通过ValueAnimator来更新此对象的Age
*/
class Person(var name: String, var age: Int) {
    override fun toString(): String {
        return "I am is $name; I am $age years old!"
    }
}

var person = Person("鲁迅认识的那只猹", 0)
ValueAnimator.ofInt(1, 50).apply {
    duration = 3000
    //动画的每一帧都会调用此监听的回调
    //我们可以在此监听中更新我们的对象
    addUpdateListener {
        person.age = it.animatedValue as Int
        Log.e("TAG", person.toString())
    }
    start()
}
/**
07-23 16:11:28.331 14623-14623/top.littledavid.studyanimation E/TAG:
-------------------------------------
07-23 16:11:28.882 14623-14623/top.littledavid.studyanimation E/TAG:
-------------------------------------
07-23 16:11:31.332 14623-14623/top.littledavid.studyanimation E/TAG:
*/
-----------------------------------

通过改变person的age属性,来改变年龄

ObjectAnimator

参数解释
1. 动画作用的对象
2. 要更改的属性
3. 设置动画渐变的数值
*/
ObjectAnimator.ofInt(dogIV, "alpha", 0, 255).setDuration(3000).start()

所以看出了ValueAnimator 和ObjectAnimator的区别了吗?

参考:https://blog.51cto.com/u_15318180/3241976

1.Animation和Animator区别
  • 对于 Animation 动画:
    • 实现机制是,在每次进行绘图的时候,通过对整块画布的矩阵进行变换,从而实现一种视图坐标的移动,但实际上其在 View内部真实的坐标位置及其他相关属性始终恒定.
  • 对于 Animator 动画:
    • Animator动画的实现机制说起来其实更加简单一点,因为他其实只是计算动画开启之后,结束之前,到某个时间点得时候,某个属性应该有的值,然后通过回调接口去设置具体值,其实 Animator 内部并没有针对某个 view 进行刷新,来实现动画的行为,动画的实现是在设置具体值的时候,方法内部自行调取的类似 invalidate 之类的方法实现的.也就是说,使用 Animator ,内部的属性发生了变化
  • 或者更简单一点说
    • 前者属性动画,改变控件属性,(比如平移以后点击有事件触发)

    • 后者补间动画,只产生动画效果(平移之后点无事件触发,前提是你fillafter=true)

2.ValueAnimator与ObjectAnimator区别
  • ValueAnimator 类是先改变值,然后手动赋值 给对象的属性从而实现动画;是间接对对象属性进行操作;
  • ObjectAnimator 类是先改变值,然后自动赋值 给对象的属性从而实现动画;是直接对对象属性进行操作;

ValueAnimator 是 ObjectAnimator 的父类,他两之间的区别是,ObjectAnimator 在ValueAnimator 的基础上,通过反射技术实现了动画功能,也就像我刚刚所举的例子,子要给了 ObjectAnimator 两个值(from,to),在确定动画类型(“scale,translate”),他就能自动生成动画。 与之形成区别,虽然我们同样需要给 ValueAnimator 传递起始和最终两个值,但是 ValueAnimator 并不会自动去执行什么,而是会通过 addUpdateListener 的监听方法,在时间插值器的作用下,有序的返回一连串数值,然后我们就可以通过这些数值,对控件进行设置。

全部评论

相关推荐

点赞 评论 收藏
转发
点赞 收藏 评论
分享
牛客网
牛客企业服务