从零开始学习自定义view【4】探索并实践Android中的自定义View动画(视图动画、属性动画、Drawable动画、过渡动画):简单而精彩

在Android开发中,我们的ui界面不全是静态的,适当添加小动画,增加用户的交互感受,细节决定成败嘛(还不是产品要加,面试要问。。👳👳)

那我们还是先从基础知识到实战的顺序开展吧。

tips:view的动画就是对某个view移动,旋转,对应到数学就是我们初中学的图像的平移和旋转。

专业地讲:View 的动画本质上就是对 View 的位置、大小、透明度、旋转角度等属性进行动态修改,从而实现动画效果。

1. 基础知识🍚

在 Android 中,View 的动画可以分为以下四类:

a. 视图动画:可以让一个 View 在屏幕上做一些简单的动画,比如渐变、旋转、移动等。例如,我们可以让一个按钮在被点击时缓慢地变透明并移动到屏幕中央。

b. 属性动画:可以对任何 View 的属性进行动画处理,比如颜色、大小、位置等。属性动画比视图动画更加灵活,可以实现更加复杂的动画效果。例如,我们可以让一个图片在屏幕上移动、旋转并渐变为不同的颜色。

c. Drawable 动画:可以让一个图片在屏幕上做一些动画效果,比如逐帧播放、闪烁等。例如,我们可以让一个笑脸图片在屏幕上不停地闪烁。

d. 过渡动画:可以让两个 View 之间实现平滑的过渡效果,比如淡入淡出、滑动等。例如,我们你可以让一个列表项在被点击时平滑地展开,或者让一个图片在被点击时平滑地弹出到全屏显示。

2. 疑惑?🍪

有的同学就有疑问了,那我们之前学校里不是学了补间动画,帧动画,你这里怎么没有啊?
所以,为什么呢?

专业地讲: 补间动画(Tween Animation)和帧动画(Frame Animation)是 Android 中的两种动画类型,它们通常被归为视图动画(View Animation)的范畴。

所以,补间动画和帧动画只是是视图动画的两种常见实现方式。他们本质上是为实现视图动画而服务的。

3. Android 中相关的类✈️

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)及以上版本中使用。

4. 实际演练一下🚢

这么多的动画,是不是脑袋都要晕了,最好的方式还是动手练习一下才能掌握。
a. 视图动画:
fade_in.xml

<?xml version="1.0" encoding="utf-8"?>
<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嘛。

4. 总结一下:🍻

  • 视图动画主要用于修改视图的外观,包括透明度、平移、缩放和旋转等属性。通过视图动画,可以为应用中的各种视图元素添加生动的效果。例如,当用户点击按钮时,可以使用缩放动画来实现按钮的放大效果,增加交互的反馈感。

  • 属性动画是一种更为灵活的动画类型,可应用于任何对象,不仅限于视图。通过属性动画,可以平滑地过渡对象的各种属性值。这使得我们开发人员可以创建更加流畅和自定义的动画效果。例如,可以使用属性动画实现一个平滑的颜色过渡效果,让界面元素在不同状态之间平滑过渡。

  • Drawable动画用于处理Drawable对象的动画效果,例如图片或动画资源。通过逐帧动画,可以创建更加生动和有趣的效果。例如,可以使用Drawable动画来实现一个循环播放的帧动画,让图标动态展示。

  • 过渡动画主要用于实现屏幕之间的平滑过渡效果。无论是在Activity之间切换,还是在Fragment或布局之间过渡,过渡动画都能提供流畅的界面转换体验。例如,可以使用淡入淡出、滑动或共享元素过渡来增强界面的平滑切换效果。

可以看出,动画类型虽多,但都大差不差的,能实现我们的需求就好。什么,不够高大上,现在不是可以使用json动画么,试试下面这个lottie动画,你会进入到动画的一个新世界的!!🍳🍳

/**
* https://github.com/airbnb/lottie-android
*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

jiet_h

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值