步骤 1: 创建心形Drawable资源

首先,我们需要创建一个心形的Drawable资源。这可以通过在res/drawable目录下创建一个XML文件来完成。

<!-- res/drawable/heart_shape.xml -->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="100dp"
    android:height="100dp"
    android:viewportWidth="100"
    android:viewportHeight="100">
    <path
        android:fillColor="#FF0000"
        android:pathData="M50,10 C30,70 20,80 50,90 C80,80 70,70 50,10 Z" />
</vector>
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

步骤 2: 创建自定义View

接下来,我们需要创建一个自定义View来绘制心形,并实现动态效果。

import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.content.Context
import android.graphics.Canvas
import android.graphics.Paint
import android.util.AttributeSet
import android.view.View
import androidx.core.content.ContextCompat
import androidx.core.graphics.ColorUtils

class HeartTree @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

    private val paint = Paint().apply {
        color = ContextCompat.getColor(context, R.color.heart_color)
        isAntiAlias = true
    }

    private val heartDrawable: VectorDrawableCompat
    private var heartSize = 50f
    private var heartX = 0f
    private var heartY = 0f
    private var heartAlpha = 255

    init {
        heartDrawable = VectorDrawableCompat.create(resources, R.drawable.heart_shape, context.theme)!!
        heartDrawable.setBounds(0, 0, heartSize.toInt(), heartSize.toInt())
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        heartDrawable.alpha = heartAlpha
        heartDrawable.draw(canvas)
    }

    fun startAnimation() {
        val xAnimator = ObjectAnimator.ofFloat(this, "heartX", 0f, width.toFloat())
        val yAnimator = ObjectAnimator.ofFloat(this, "heartY", 0f, height.toFloat())

        val alphaAnimator = ObjectAnimator.ofInt(this, "heartAlpha", 0, 255).apply {
            addUpdateListener { animation ->
                heartAlpha = animation.animatedValue as Int
                invalidate()
            }
        }

        val animatorSet = AnimatorSet().apply {
            playTogether(xAnimator, yAnimator, alphaAnimator)
            duration = 5000
            repeatCount = ObjectAnimator.INFINITE
            repeatMode = ObjectAnimator.REVERSE
        }

        animatorSet.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationEnd(animation: Animator) {
                // 动画结束后重新开始
                animatorSet.start()
            }
        })

        animatorSet.start()
    }

    fun setHeartX(value: Float) {
        heartX = value
        invalidate()
    }

    fun setHeartY(value: Float) {
        heartY = value
        invalidate()
    }

    fun setHeartAlpha(value: Int) {
        heartAlpha = value
        invalidate()
    }
}
  • 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.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.

步骤 3: 创建布局

接下来,我们需要创建一个布局文件来放置自定义View

<!-- res/layout/activity_main.xml -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center"
    android:padding="16dp">

    <com.example.yourapp.HeartTree
        android:id="@+id/heart_tree"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</LinearLayout>
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

步骤 4: 实现逻辑

MainActivity中,我们需要初始化自定义View,并启动动画。

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import com.example.yourapp.HeartTree
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    private lateinit var heartTree: HeartTree

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        heartTree = findViewById(R.id.heart_tree)

        // 启动动画
        heartTree.startAnimation()
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.

说明

  • Drawable资源: 我们创建了一个心形的Drawable资源。
  • 自定义View: 在自定义View中实现了心形的绘制和动画效果。
  • 布局文件: 在布局文件中定义了一个自定义View
  • 启动动画: 在MainActivity中初始化自定义View,并启动动画。

这个示例展示了如何在Android中创建一个动态的心形树效果。你可以根据需要调整动画参数,例如改变动画的速度、方向或添加更多的心形元素。