Android 抖音爱心动画,Android实现抖音心形函数

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

心形函数公式

公式 :

f621095ad128?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

心形公式

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

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

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

Android实现

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

先看动画效果:

f621095ad128?utm_campaign=maleskine&utm_content=note&utm_medium=seo_notes&utm_source=recommendation

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?) {

}

}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值