7.动画与图形渲染

  • 动画框架
    • View Animation(视图动画):包括补间动画和帧动画。
    • Property Animation(属性动画):通过ValueAnimatorObjectAnimator实现。
  • 图形渲染
    • Skia:2D图形渲染引擎。
    • OpenGL ES:3D图形渲染支持。

补间动画:有起始状态和终止状态(只是一个动画效果 视觉效果 没有真正改变控件的属性)

适用情况:需要实现简单的基本动画效果,或者需要快速实现视图的基本动画效果。

补间动画

补间动画(TweenAnimaion)四种常用实现:

  1. AlphaAnimation (透明动画)
  • fromAlpha:动画开始时视图的透明度(取值范围: -1 ~ 1)
  • toAlpha:动画结束时视图的透明度(取值范围: -1 ~ 1)
  1. RotateAnimation (旋转动画)
  • fromDegrees :动画开始时 视图的旋转角度(正数 = 顺时针,负数 = 逆时针)
  • toDegrees :动画结束时 视图的旋转角度(正数 = 顺时针,负数 = 逆时针)
  • pivotXType :旋转轴点的x坐标的模式
  • pivotXValue :旋转轴点x坐标的相对值
  • pivotYType :旋转轴点的y坐标的模式
  • pivotYValue :旋转轴点y坐标的相对值

pivotXType = Animation.ABSOLUTE:旋转轴点的x坐标= View左上角的原点 在x方向 加上 pivotXValue 数值的点(y方向同理)
pivotXType = Animation.RELATIVE_TO_SELF:旋转轴点的x坐标= View左上角的原点在x方向加上自身宽度乘上pivotXValue数值的值(y方向同理)
pivotXType = Animation.RELATIVE_TO_PARENT:旋转轴点的x坐= View左上角的原点在x方向加 父控件宽度乘上pivotXValue数值的值 (y方向同理)

  1. ScaleAnimation (缩放动画)
    参数:
  • fromX :动画在水平方向X的起始缩放倍数
  • toX :动画在水平方向X的结束缩放倍数
  • fromY :动画开始前在竖直方向Y的起始缩放倍数
  • toY:动画在竖直方向Y的结束缩放倍数
  • pivotXType:缩放轴点的x坐标的模式
  • pivotXValue:缩放轴点x坐标的相对值
  • pivotYType:缩放轴点的y坐标的模式
  • pivotYValue:缩放轴点y坐标的相对值

pivotXType = Animation.ABSOLUTE:缩放轴点的x坐标 = View左上角的原点 在x方向 加上 pivotXValue 数值的点(y方向同理)
pivotXType = Animation.RELATIVE_TO_SELF:缩放轴点的x坐标=View左上角的原点 在x方向加上自身宽度乘上 pivotXValue 数值的值(y方向同理)
pivotXType = Animation.RELATIVE_TO_PARENT:缩放轴点的x坐标=View左上角的原点 在x方向加上父控件宽度乘上 pivotXValue 数值的值 (y方向同理)

  1. TranslateAnimation (平移动画)
  • fromXDelta :视图在水平方向x 移动的起始值
  • toXDelta :视图在水平方向x 移动的结束值
  • fromYDelta :视图在竖直方向y 移动的起始值
  • toYDelta:视图在竖直方向y 移动的结束值

动画的同一属性
以下参数是4种动画效果的公共属性,即都有的属性(即可写在set中也可以在自己的属性中写)
android:duration=”3000” // 动画持续时间(ms),必须设置,动画才有效果
android:startOffset =”1000” // 动画延迟开始时间(ms)
android:fillBefore = “true” // 动画播放完后,视图是否会停留在动画开始的状态,默认为true
android:fillAfter = “false” // 动画播放完后,视图是否会停留在动画结束的状态,优先于fillBefore值,默认为false
android:fillEnabled= “true” // 是否应用fillBefore值,对fillAfter值无影响,默认为true
android:repeatMode= “restart” // 选择重复播放动画模式,restart代表正序重放,reverse代表倒序回放,默认为restart
android:repeatCount = “0” // 重放次数(所以动画的播放次数=重放次数+1),为infinite时无限重复
android:interpolator = @[package:]anim/interpolator_resource // 插值器,即影响动画的播放速度

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
fun slideOutToTopAnimation(onEnd:()->Unit = {}):Animation{
return TranslateAnimation(
Animation.RELATIVE_TO_SELF,
fromXValue: 0f,
Animation.RELATIVE_TO_SELF,
toXValue: 0f,
Animation.RELATIVE_TO_SELF,
fromYValue: 0f,
Animation.RELATIVE_TO_SELF,
toYValue: -1f
).apply { this: TranslateAnimation
duration = 200
setAnimationListener(Object:Animation.AnimationListener{
override fun onAnimationStart(animation: Animation?){

}
override fun onAnimationEnd(animation: Animation?){
onEnd()
}
override fun onAnimationRepeat(animation: Animation?){

}
})
}
}

1.AnimationSet(代码定义)

在Android中,AnimationSet是一个用于组合多个动画效果的类。通过AnimationSet,可以将多个动画效果按照一定的顺序或同时播放。
AnimationSet可以包含多个Animation对象,每个Animation对象可以是AlphaAnimation(透明度动画)、ScaleAnimation(缩放动画)、TranslateAnimation(位移动画)或RotateAnimation(旋转动画)等。

以下是AnimationSet的常用方法及其作用:

  1. addAnimation(animation: Animation):向AnimationSet中添加动画效果。
  2. setDuration(durationMillis: Long):设置动画的持续时间,单位为毫秒。
  3. setFillAfter(fillAfter: Boolean):设置动画结束后是否保持最后的状态。
  4. setFillBefore(fillBefore: Boolean):设置动画开始前是否使用起始状态。
  5. setInterpolator(interpolator: Interpolator):设置动画的插值器,用于控制动画的变化速率。
  6. setRepeatCount(repeatCount: Int):设置动画的重复次数,可以是一个正整数或Animation.INFINITE。
  7. setStartOffset(offsetMillis: Long):设置动画开始之前的延迟时间,单位为毫秒。
  8. setStartTime(startTimeMillis: Long):设置动画开始的时间,单位为毫秒。
  9. initialize(width: Int, height: Int, parentWidth: Int, parentHeight: Int):初始化动画的尺寸信息,通常在动画开始前调用。

下面是一个使用Kotlin语言创建 AnimationSet 并添加动画的示例:

1
2
3
4
5
6
7
8
9
10
11
val animationSet = AnimationSet(true).apply {
addAnimation(AlphaAnimation(0.0f, 1.0f).apply {
duration = 1000
})

addAnimation(ScaleAnimation(0.0f, 1.0f, 0.0f, 1.0f).apply {
duration = 1000
})
}

view.startAnimation(animationSet)

在这个示例中,我们创建了一个包含透明度动画和缩放动画的AnimationSet,并将其应用到一个View上。

AnimationSet 类中常用的属性有:

  1. animations :用于存储AnimationSet中包含的动画效果列表。
  2. duration :动画的持续时间,单位为毫秒。
  3. fillAfter :动画结束后是否保持最后的状态。
  4. fillBefore:动画开始前是否使用起始状态。
  5. interpolator :动画的插值器,用于控制动画的变化速率。
  6. repeatCount :动画的重复次数,可以是一个正整数或Animation.INFINITE。
  7. startOffset :动画开始之前的延迟时间,单位为毫秒。
  8. startTime :动画开始的时间,单位为毫秒。

2.从 anim 资源中加载动画资源(xml创建)

fillAfter :动画结束后是否保持最终状态

AnimationUtils.loadAnimation 是一个用于从资源文件中加载动画资源的静态方法。
它会解析并加载指定的资源文件,并返回一个 Animation 对象,该对象表示了加载的动画资源。
通过调用此方法,可以在Android应用程序中直接使用 XML 定义的动画资源,而无需手动创建和配置动画对象。

例如,可以通过调用AnimationUtils.loadAnimation方法从res/anim文件夹中加载一个定义好的动画资源,并将其应用于一个View对象:

1
2
3
4
5
6
7
8
Object IndicatorAnimation{
fun startAnimation(target:View){
AnimationUtils.loadAnimation(target.context, R.anim.fade_in).apply{
fillAfter = true
target.startAnimation(this)
}
}
}

在上述示例中,loadAnimation方法加载了res/anim文件夹中的fade_in.xml动画资源,并将其应用于名为view的View对象,使其显示一个淡入的动画效果。

ValueAnimator

针对某个控件的某个属性进行操作(通过改变属性的值来实现动画效果)
会改变属性值 控件真正移动了

适用情况:需要实现复杂的动画效果,或需要对视图的属性进行动态改变和交互。

ValueAnimator 是一个用于执行属性动画的类,可以用来改变数值属性的值并在一定时间内进行动画过渡。

ObjectAnimator 继承自 ValueAnimator
val animator = ObjectAnimator.ofFloat(view, "propertyName", startValue, endValue)
view :要执行动画的 View 对象。
“propertyName” :要执行动画的属性名称,如 “alpha”、”rotation”、”translationX”、”scaleX” 等。
startValue :动画起始值。
endValue :动画结束值。

ValueAnimator
这是一个动画,不断产生一系列的值

1
2
3
ValueAnimator.ofArgb()  //颜色的变化
ValueAnimator.ofFloat() //得到某区间的数(浮点数)
ValueAnimator.ofInt() //得到某区间的数(整数)

创建动画

步骤:

第一步 创建动画对象

ValueAnimator

  1. duration 持续时间

  2. repeatCount 重复次数

    • 0 不重复
    • ValueAnimator.INFINITE 无限次
  3. repeatMode 重复模式

    • ValueAnimator.RESTART 重新开始
    • ValueAnimator.REVERSE 反转
  4. interpolator 插值器(控制动画的速度变化)

    • LinearInterpolator() 匀速进行
    • AccelerateInterpolator() 在动画开始时加速
    • DecelerateInterpolator() 在动画结束时减速
    • BounceInterpolator() 回弹效果
  5. startDelay 延迟时间 指定在调用 start 方法后多久开始执行动画

  6. start()启动动画

第二步 监听 value 变化

addUpdateListener{} //会返回更新值之后的 ValueAnimator

  • animatedValue 是 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
//1. 创建动画对象
//创建 ValueAnimator 的对象,并设置动画的起始值和结束值
val angleAnimator = ValueAnimator.ofFloat(0f,360f)

angleAnimator.duration = 2000
angleAnimator.repeatCount = 2
angleAnimator.repeatMode = ValueAnimator.REVERSE
angleAnimator.interpolator = BounceInterpolator()
angleAnimator.startDelay = 500

angleAnimator.start() //启动动画


//2. 监听value变化
//监听value变化 这个值是不断在更新变化的
angleAnimator.addUpdateListener {
//获取当前的值 转化成Float类型
mSweepAngle = it.animatedValue as Float

//drawText数值随动画变化
val num = ((it.animatedValue / 360) * 100).toInt()
rateText = "$num%"

invalidate() //告诉View刷新更新的值
}

用apply修改

1
2
3
4
5
6
7
8
9
ValueAnimator.ofFloat(0f,360f).apply{
duration = 500
addUpdateListener{
mSweepAngle = it.animatedValue as Float //得到当前过程值
invalidate() //告诉View刷新更新的值
}
start()
}

AnimatorSet

AnimatorSet 是一个用于 管理多个动画一起播放或按顺序播放 的类。
可以使用 AnimatorSet 来组合多个属性动画,使它们按照指定的顺序或同时播放。

AnimatorSet() 管理所有动画的播放形式

  • playTogether(Animator…) 一起

  • playSequentially(Animator…) 顺序

  • setDuration(Long): 设置AnimatorSet的持续时间

  • start(): 启动AnimatorSet中的动画

  • pause():暂停

  • cancel(): 取消AnimatorSet中的动画

  • addListener(Animator.AnimatorListener): 添加动画监听器

  • duration

  • interpolator

1
2
3
4
5
6
7
8
9
10
11
12
13
AnimatorSet.playSequentially()


AnimatorSet().apply {
playSequentially(radiusAnim,moveAnim) //传入动画

//监听动画事件 改变画笔颜色
addListener( onEnd = {
mRoundRectPaint.color = Color.parseColor("#00BAAD")
invalidate()//颜色变了 再重新画一下
})
start()
}

这个也是属性动画:

1
2
3
4
5
6
7
binding.colorRecyclerView  
.animate()
.translationY(requireActivity().dp2px( dp: -78).toFloat()

binding.colorRecyclerView
.animate()
.rotation( value: 360f)
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
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
* 管理封面图片的旋转动画
* 开始
* 暂停
* 恢复
* 取消
*/
class AlbumRotateAnimation(val target: View) {
private var mAnimation:ObjectAnimator? = null

fun start(){
if (mAnimation!= null && mAnimation!!.isPaused){
resume()
return
}

if (mAnimation!= null && mAnimation!!.isStarted){
release()
}
mAnimation = ObjectAnimator.ofFloat(target,"rotation",0f,360f).apply {
duration = 5000
repeatMode = ValueAnimator.RESTART
repeatCount = ValueAnimator.INFINITE //无限
interpolator = LinearInterpolator()
start()
}
}
fun reset(){
release()
}

fun pause(){
mAnimation?.pause()
}
fun resume(){
mAnimation?.resume()
}
fun release(){
mAnimation?.cancel()
mAnimation = null
}
}

Animator

Animator 抽象类
常用方法:
void cancel (): 取消动画。
void end ():让动画到达最后一帧。
void start():开始动画。
void pause():暂停动画。
void resume():继续动画。
void reverse ():反向播放动画。
boolean isRunning():是否在运行中。
boolean isStarted():是否已经开始。
boolean isPaused()

共享动画

使用共享元素转换
(切换顺滑)
(先确定哪两个控件之间需要共享动画)
1.给两个控件添加transitionName

1
android:transitionName="little"

2.切换动画时设置A Fragment中哪个控件和 B Fragment中的哪个控件共享动画
addSharedElement(view1,”big”)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view = inflater.inflate(R.layout.fragment_first, container, false)
val view1 = view.findViewById<ImageView>(R.id.view1)

view.setOnClickListener {
parentFragmentManager.commit {
setCustomAnimations(android.R.anim.fade_in,android.R.anim.fade_out)
replace(R.id.fragmentContainerView,SecondFragment())
setReorderingAllowed(true)
addSharedElement(view1,"big")
addToBackStack(null)
}
}
return view
}

3.到目的地 Fragment 的 onCreate 中配置动画效果

1
2
3
4
5
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
sharedElementEnterTransition = TransitionInflater.from(requireContext()).inflateTransition(android.R.transition.move)
//(在fragment中使用activity获取当前这个fragment依附的activity对象)
}

自行配置转换动画效果
res -> New -> Android Resource Directory(transition)
transition -> New -> Android Resource File
Root element:
transitionSet
transitionManager

面试

3.1 Android 补间动画和属性动画的区别?(享学)

  1. 实现原理:补间动画仅修改 View 的绘制效果,不改变真实属性;属性动画通过反射动态修改对象的属性值。
  2. 功能范围:补间动画支持四种固定效果(透明度、旋转等),属性动画可操作任何属性。
  3. 交互性:补间动画的点击区域不变,属性动画会同步更新交互区域。
  4. 兼容性:补间动画全版本支持,属性动画需 API 11+。
    实际开发中,简单视觉效果用补间动画,复杂交互或属性变化必须用属性动画。”

Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.

扫一扫,分享到微信

微信分享二维码
  • Copyrights © 2023-2025 Annie
  • Visitors: | Views:

嘿嘿 请我吃小蛋糕吧~

支付宝
微信