在本文中,我们将使用 android 属性动画创建一个星雨。我们将创建一个稍微复杂的动画,为多个对象的多个属性设置动画。对于此效果,单击按钮将创建一个随机大小的星形,该星形将添加到背景容器中,刚好在容器顶部的视野之外。星星将通过加速下降到屏幕底部。星星坠落时也会旋转。下面给出了一个示例 GIF,以了解我们将在本文中做什么。请注意,我们将使用Kotlin语言来实现这个项目。
分步实施
第 1 步:创建一个新项目
要在 Android Studio 中创建新项目,请参阅如何在 Android Studio 中创建/启动新项目。请注意,选择Kotlin作为编程语言。
第 2 步:我们需要一些局部变量来保存状态。
- 对 Starfield ViewGroup 的引用,它只是当前星视图的父级。
- 该容器的宽度和高度将用于计算流星的最终平移值。
- 星星的默认宽度和高度,稍后将使用比例因子更改以获得不同大小的星星。
val container = star.parent as ViewGroup
val containerW = container.width
val containerH = container.height
var starW: Float = star.width.toFloat()
创建一个新的视图来保存星星,因为它是一个 VectorDrawable 资产,利用 AppCompatImageView,它能够承载这种资源。创建星星并将其添加到背景容器中。
val newStar = AppCompatImageView(this)
newStar.setImageResource(R.drawable.ic_star)
newStar.layoutParams = FrameLayout.LayoutParams(FrameLayout.LayoutParams.WRAP_CONTENT,
FrameLayout.LayoutParams.WRAP_CONTENT)
第 3 步:调整和定位星形
我们还没有定义图像在容器中的位置,所以它默认定位在 (0, 0) 处。我们将在此步骤中修复它。
(i)设置星星的大小。将星星修改为随机大小,从其默认大小的 0.1 倍到 1.6 倍。使用此比例因子来更改缓存的宽度/高度值。
newStar.scaleX = Math.random().toFloat() * 1.5f + .1f
newStar.scaleY = newStar.scaleX
starW *= newStar.scaleX
starH *= newStar.scaleY
您现在已经缓存了存储在 starW 和 starH 中的恒星像素 H/W:
(ii)现在定位新星。它应该随机出现在水平左边缘到右边缘之间的某处。下面的代码使用星星的宽度将其从左侧屏幕的一半 (-starW / 2) 定位到右侧屏幕的一半(星星位于 (containerW – starW / 2))。
newStar.translationX = Math.random().toFloat() * containerW – starW / 2
第 4 步:为星星旋转和下落创建动画师
是时候制作动画了。恒星应该在向下坠落时旋转。我们可以一起为两个属性设置动画。旋转将使用平滑的线性运动(在整个旋转动画中以恒定速率移动),而下降动画将使用加速运动(模拟重力以恒定更快的速率向下拉动恒星)。因此,您将创建两个动画师并为每个动画师添加一个插值器。
(i)首先,创建两个动画师及其插值器:
val mover = ObjectAnimator.ofFloat(newStar, View.TRANSLATION_Y, -starH, containerH + starH)
mover.interpolator = AccelerateInterpolator(1f) // causes a gentle acceleration motion
val rotator = ObjectAnimator.ofFloat(newStar, View.ROTATION,
(Math.random() * 1080).toFloat()) // star rotates a random amount between 0 and 1080 degrees
rotator.interpolator = LinearInterpolator() //the rotation will proceed at a constant rate as the star falls
移动动画负责使星星“坠落”。它为 TRANSLATION_Y 属性设置动画,但会导致垂直而不是水平运动。代码从 -starH 动画到 (containerH + starH),这有效地将其放置在顶部的容器外,并将其移动到底部的容器外,如下所示:
第 5 步:与 AnimatorSet 并行运行动画
现在是时候将这两个动画师放在一个 AnimatorSet 中了。它基本上是一组动画,以及有关何时运行这些动画的说明。它可以并行播放动画。
(i)创建 AnimatorSet 并将子动画师添加到其中。默认动画时间 300 毫秒对于坠落的星星来说太快了,所以将持续时间设置为 500 到 2000 毫秒之间的随机数,这样星星可以以不同的速度坠落。
val set = AnimatorSet()
set.playTogether(mover, rotator)
set.duration = (Math.random() * 1500 + 500).toLong()
(ii)一旦 newStar 从屏幕底部掉落,应将其从容器中取出。设置一个简单的侦听器以等待动画结束并将其删除。然后开始动画。
set.addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
container.removeView(newStar)
}
})
set.start()
导航到app > res > layout > activity_main.xml并将以下代码添加到该文件中。以下是activity_main.xml文件的完整代码。
XML
Kotlin
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.view.animation.AccelerateInterpolator
import android.view.animation.LinearInterpolator
import android.widget.Button
import android.widget.FrameLayout
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.AppCompatImageView
class MainActivity : AppCompatActivity() {
lateinit var showerButton: Button
lateinit var star: ImageView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
showerButton = findViewById
转到MainActivity.kt文件并参考以下代码。下面是MainActivity.kt文件的完整代码。代码中添加了注释以更详细地理解代码。
科特林
import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import android.view.animation.AccelerateInterpolator
import android.view.animation.LinearInterpolator
import android.widget.Button
import android.widget.FrameLayout
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.AppCompatImageView
class MainActivity : AppCompatActivity() {
lateinit var showerButton: Button
lateinit var star: ImageView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
showerButton = findViewById
现在,运行您的应用程序。您可以多次点击“STAR SHOWER ”按钮,每次都会创建一个新的明星和新的动画。
输出:
源代码:点击这里
想要一个更快节奏和更具竞争力的环境来学习 Android 的基础知识吗?
单击此处前往由我们的专家精心策划的指南,旨在让您立即做好行业准备!