美文网首页
Android实现抖音心形函数

Android实现抖音心形函数

作者: JimmieYang | 来源:发表于2019-02-02 15:50 被阅读91次

刷抖音的时候,无意间刷到 心形函数的动画,觉得很有意思, 就简单的用Android的方式实现了一下.

心形函数公式

公式 :

心形公式

X的取值范围:[-1.81,1.81],该取值范围是保证正弦函数有效取值范围。

我们可以通过参数 a 的取值, 来形成不同的心形轮廓, 进而形成动画效果.

有了以上的认识,我们就是可开始编写Android代码了.

Android实现

代码使用 Kotlin来编写自定义View.个人觉得 只有心还不够, 动画结束需要逐渐显示文字,来达到表白的效果.

先看动画效果:


heart.gif

然后贴上代码实现:

class HeartView(context: Context, attrs: AttributeSet) : BaseView(context, attrs),
    ValueAnimator.AnimatorUpdateListener, Animator.AnimatorListener {

    var text = "Hello Android"

    private val animator = ValueAnimator.ofInt(3_000)
    private val path = Path()
    private var heartDrawing = false
    private var heart = 0.1f
    private var pct = 0f

    init {
        paint.strokeWidth = 4 * dp
        paint.textSize = 30 * dp
        paint.textAlign = Paint.Align.CENTER

        animator.interpolator = LinearInterpolator()
        animator.addUpdateListener(this)
        animator.addListener(this)
    }

    fun startHeart() {
        heartDrawing = true
        animator.cancel()
        animator.duration = 3_000
        animator.start()
    }

    override fun onDraw(canvas: Canvas) {
        path.reset()
        paint.color = Color.RED
        paint.style = Paint.Style.STROKE

        val padding = 20
        val halfWidth = width / 2 - padding
        val halfHeight = height / 2
        // 根据X坐标,计算出Y坐标, 将其映射到屏幕坐标后,用path连接
        for (index in 0..(width - padding * 2)) {
            val x = (index - halfWidth) * 1.81 / halfWidth
            val y = -getHeartY(x, heart) * height / 6 + halfHeight
            if (index == 0) {
                path.moveTo(index.toFloat() + padding, y.toFloat())
            } else {
                path.lineTo(index.toFloat() + padding, y.toFloat())
            }
        }
        canvas.drawPath(path, paint)

        // 结束后写文字
        if (!heartDrawing) {
            val textWidth = paint.measureText(text)
            val left = width / 2f - textWidth / 2f
            val top = height * 0.4f - 0.9f * paint.textSize

            canvas.clipRect(left, top, left + textWidth * pct, top + 1.2f * paint.textSize)

            paint.color = Color.WHITE
            paint.style = Paint.Style.FILL
            canvas.drawText(text, width / 2f, height * 0.4f, paint)
        }
    }

    private fun getHeartY(x: Double, a: Float): Double {
        return Math.pow(x * x, 1.0 / 3) + 0.9 * Math.sqrt(3.3 - x * x) * Math.sin(a * Math.PI * x)
    }


    override fun onAnimationUpdate(animation: ValueAnimator) {
        val value = animation.animatedValue as Int
        if (value == 0) return
        if (heartDrawing) heart = value * 0.01f
        else {
            pct = value / 3000f
        }
        invalidate()
    }

    override fun onDetachedFromWindow() {
        animator.cancel()
        animator.removeAllUpdateListeners()
        animator.removeAllListeners()
        super.onDetachedFromWindow()
    }

    override fun onAnimationEnd(animation: Animator?) {
        if (heartDrawing) {
            heartDrawing = false

            animation?.duration = 3_000
            animation?.start()
        }
    }

    override fun onAnimationStart(animation: Animator?) {
    }

    override fun onAnimationRepeat(animation: Animator?) {
    }

    override fun onAnimationCancel(animation: Animator?) {
    }
}

这样就实现了, 是不是觉得很简单.

相关文章

网友评论

      本文标题:Android实现抖音心形函数

      本文链接:https://www.haomeiwen.com/subject/efissqtx.html