在Android开发中,我们的ui界面不全是静态的,适当添加小动画,增加用户的交互感受,细节决定成败嘛(还不是产品要加,面试要问。。)
那我们还是先从基础知识到实战的顺序开展吧。
tips:view的动画就是对某个view移动,旋转,对应到数学就是我们初中学的图像的平移和旋转。
专业地讲:View 的动画本质上就是对 View 的位置、大小、透明度、旋转角度等属性进行动态修改,从而实现动画效果。
在 Android 中,View 的动画可以分为以下四类:
a. 视图动画:可以让一个 View 在屏幕上做一些简单的动画,比如渐变、旋转、移动等。例如,我们可以让一个按钮在被点击时缓慢地变透明并移动到屏幕中央。
b. 属性动画:可以对任何 View 的属性进行动画处理,比如颜色、大小、位置等。属性动画比视图动画更加灵活,可以实现更加复杂的动画效果。例如,我们可以让一个图片在屏幕上移动、旋转并渐变为不同的颜色。
c. Drawable 动画:可以让一个图片在屏幕上做一些动画效果,比如逐帧播放、闪烁等。例如,我们可以让一个笑脸图片在屏幕上不停地闪烁。
d. 过渡动画:可以让两个 View 之间实现平滑的过渡效果,比如淡入淡出、滑动等。例如,我们你可以让一个列表项在被点击时平滑地展开,或者让一个图片在被点击时平滑地弹出到全屏显示。
有的同学就有疑问了,那我们之前学校里不是学了补间动画,帧动画,你这里怎么没有啊?
所以,为什么呢?
专业地讲: 补间动画(Tween Animation)和帧动画(Frame Animation)是 Android 中的两种动画类型,它们通常被归为视图动画(View Animation)的范畴。
所以,补间动画和帧动画只是是视图动画的两种常见实现方式。他们本质上是为实现视图动画而服务的。
a. 视图动画:
AlphaAnimation:控制 View 的透明度;ScaleAnimation:控制 View 的缩放比例;TranslateAnimation:控制 View 的平移;RotateAnimation:控制 View 的旋转角度。
这些动画都是通过 AnimationUtils 类来创建和管理的。例如,我们可以使用 AnimationUtils.loadAnimation() 方法来加载一个 XML 文件,其中定义了一个或多个视图动画。
b. 属性动画:
ValueAnimator:可以对一个数值范围进行动画处理;ObjectAnimator:可以对任意对象的属性进行动画处理;AnimatorSet:可以将多个 Animator 组合在一起,实现复杂的动画效果。
这些动画都是通过 Animator 类及其子类来实现的,我们可以通过代码来动态创建和管理它们。
c. Drawable 动画:
AnimationDrawable:可以播放一组连续的图片,实现帧动画效果;LevelListDrawable:可以根据 View 的状态(比如按下、选中等)来切换不同的 Drawable。
这些动画都是通过 Drawable 类及其子类来实现的,我们可以通过代码来动态创建和管理它们。
d. 过渡动画:
Transition:可以实现两个 View 之间平滑的过渡效果;TransitionSet:可以将多个 Transition 组合在一起,实现复杂的过渡效果。
这些动画都是通过 Transition 类及其子类来实现的,我们可以通过代码或 XML 文件来定义和管理它们。需要注意的是,过渡动画只能在 Android 5.0(API 级别 21)及以上版本中使用。
这么多的动画,是不是脑袋都要晕了,最好的方式还是动手练习一下才能掌握。
a. 视图动画:
fade_in.xml
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator"
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:duration="1000" />
android:interpolator:指定动画的插值器,这里使用了accelerate_interpolator,表示加速插值器,使动画逐渐加速。
android:fromAlpha:指定动画的起始透明度,这里为完全透明(0.0)。
android:toAlpha:指定动画的结束透明度,这里为完全不透明(1.0)。
android:duration:指定动画的持续时间,这里为1秒(1000毫秒)。
通过加载这个fade_in.xml视图动画资源文件,并将其应用于视图对象,可以实现一个淡入的效果,让视图从完全透明逐渐变为完全不透明。
class MainActivity : AppCompatActivity() {
private val viewBinding by lazy(LazyThreadSafetyMode.NONE) {
XXXBinding.inflate(LayoutInflater.from(requireContext()))
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(viewBinding.root)
// 加载视图动画资源文件
val animation = AnimationUtils.loadAnimation(this, R.anim.fade_in)
// 启动动画
viewBinding.ivAnim.startAnimation(animation)
}
}
b. 属性动画:
这种类型的动画在我目前的项目中用的比较多,相信大家经常打交道的也是这种类型的动画吧。
例如,当我们想使得某个执行放大的动画时,我们通常这样做:
val animator = ObjectAnimator.ofPropertyValuesHolder(
customView,
PropertyValuesHolder.ofFloat("scaleX", 1.0f, 1.2f),
PropertyValuesHolder.ofFloat("scaleY", 1.0f, 1.2f)
)
// 开始动画
animator.start()
// 结束动画
animator.cancel()
现在提供给大家另一种kotlin写法思路:相当于也是一种模板,亦或是我们习惯的一种方式:
fun View.animClickScale(scale: Float = 1.2f): ValueAnimator {
return ObjectAnimator.ofPropertyValuesHolder(
this,
PropertyValuesHolder.ofFloat("scaleX", scale),
PropertyValuesHolder.ofFloat("scaleY", scale)
).apply {
duration = 200L
addListener(object : Animator.AnimatorListener {
override fun onAnimationStart(animation: Animator?) {
}
override fun onAnimationEnd(animation: Animator?) {
}
override fun onAnimationCancel(animation: Animator?) {
rotation = 45f
}
override fun onAnimationRepeat(animation: Animator?) {
}
})
}
}
// 使用
val anim = customView.animClickScale()
anim.start()
// 取消
anim.cancel()
我们首先给View添加了我们自定义的扩展函数animClickScale,然后我们使用的时候,由于我们的customView肯定继承自View,所以直接使用,这样的话,我们逻辑部分的代码量就会少很多,去哪里了呢,跑到其他类里了哇。
c. 属性动画:
在 res/drawable 目录下创建一个 animation_list.xml 文件,包含以下内容:
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="@drawable/animation_frame_1" android:duration="100" />
<item android:drawable="@drawable/animation_frame_2" android:duration="100" />
<item android:drawable="@drawable/animation_frame_3" android:duration="100" />
<item android:drawable="@drawable/animation_frame_4" android:duration="100" />
animation-list>
我们定义了一个 AnimationDrawable 对象,它包含了四个帧(即四个 drawable 对象),并且每个帧之间的时间间隔为 100 毫秒。我们将 oneshot 属性设置为 false,来使动画循环播放。
在布局文件中,将 ImageView 控件的 android:src 属性设置为 animation_list,如下所示:
<ImageView
android:id="@+id/iv_anim"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:src="@drawable/animation_list" />
在 Activity 中,获取 ImageView 控件的引用,并将其转换为 AnimationDrawable 对象。然后,调用 start() 方法开始:
private val viewBinding by lazy(LazyThreadSafetyMode.NONE) {
XXXBinding.inflate(LayoutInflater.from(requireContext()))
}
val animDrawable = viewBinding.ivAnim.drawable as AnimationDrawable
animDrawable .start()
当然,我们也可以使用我们上面的方法,代码的规范化可以适当增强代码的可读性,健壮性,可扩展性等等,细节!!
fun ImageView.animDraw(): AnimationDrawable {
return this.drawable as AnimationDrawable
}
private val viewBinding by lazy(LazyThreadSafetyMode.NONE) {
XXXBinding.inflate(LayoutInflater.from(requireContext()))
}
val animDrawable = viewBinding.ivAnim.animDraw()
animDrawable .start()
也可根据自己的习惯,代码就像写字一样,一样的风格放在一块儿就很工整很好看,否则就会有点四不像啦。
d. 过渡动画:
在Android 中,我们Activity的切换淡入淡出效果就是用的过渡动画来实现的。
进入/退出动画:当一个 Activity 进入或退出屏幕时,可以使用视图动画来添加一些过渡效果,比如从屏幕边缘滑入或滑出,或者淡入淡出。
slide_in_right.xml:
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromXDelta="100%p"
android:toXDelta="0"
android:duration="300" />
<alpha
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:duration="300" />
set>
slide_out_left.xml:
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromXDelta="0"
android:toXDelta="-100%p"
android:duration="300" />
<alpha
android:fromAlpha="1.0"
android:toAlpha="0.0"
android:duration="300" />
set>
其中,translate 元素表示平移动画,alpha 元素表示透明度动画,通过 fromXDelta、toXDelta、fromAlpha、toAlpha 等属性来设置动画的起始和结束状态。
接下来,在 Activity 中设置进入和退出动画。在 onCreate() 方法中,添加以下代码:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 设置进入动画
overridePendingTransition(R.anim.slide_in_right, R.anim.slide_out_left)
}
在 onDestroy() 方法中,添加以下代码:
override fun onDestroy() {
super.onDestroy()
// 设置退出动画
overridePendingTransition(R.anim.slide_in_right, R.anim.slide_out_left)
}
这里使用 overridePendingTransition() 方法来设置进入和退出动画,分别传入进入动画和退出动画的资源 ID。
这样,在 Activity 进入和退出时,就会播放对应的动画效果。
然后又有疑问啦!!
不是说是view的动画蛮,怎么设置的Activity动画呢?
那我们在Activity的onCreate里不是要setContentView()么,我们会传入我们的布局文件,而布局文件是啥,溯其源头,不还是view嘛。
视图动画主要用于修改视图的外观,包括透明度、平移、缩放和旋转等属性。通过视图动画,可以为应用中的各种视图元素添加生动的效果。例如,当用户点击按钮时,可以使用缩放动画来实现按钮的放大效果,增加交互的反馈感。
属性动画是一种更为灵活的动画类型,可应用于任何对象,不仅限于视图。通过属性动画,可以平滑地过渡对象的各种属性值。这使得我们开发人员可以创建更加流畅和自定义的动画效果。例如,可以使用属性动画实现一个平滑的颜色过渡效果,让界面元素在不同状态之间平滑过渡。
Drawable动画用于处理Drawable对象的动画效果,例如图片或动画资源。通过逐帧动画,可以创建更加生动和有趣的效果。例如,可以使用Drawable动画来实现一个循环播放的帧动画,让图标动态展示。
过渡动画主要用于实现屏幕之间的平滑过渡效果。无论是在Activity之间切换,还是在Fragment或布局之间过渡,过渡动画都能提供流畅的界面转换体验。例如,可以使用淡入淡出、滑动或共享元素过渡来增强界面的平滑切换效果。
可以看出,动画类型虽多,但都大差不差的,能实现我们的需求就好。什么,不够高大上,现在不是可以使用json动画么,试试下面这个lottie动画,你会进入到动画的一个新世界的!!
/**
* https://github.com/airbnb/lottie-android
*/