【情人节用Compose给女神写个爱心动画APP】

情人节用Compose给女神写个爱心动画APP

  • 前言
  • 涉及知识点
  • 实现思路
  • 实现过程
    • 绘制爱心
    • 创建动画效果
    • Preview预览效果
  • 完整源码
  • 彩蛋

前言

前一阵子看电视里的学霸用代码写了个炫酷的爱心,网上有很多js和python的源码,复制粘贴就能拥有,但是Android的好像还没有人写过。今天正好是情人节,咱们来用Compose写一个简单的爱心动画,告诉女神们,咱们程序猿也有自己的浪漫(/手动狗头)

废话不多说,直接看效果:
(源码在最后)
【情人节用Compose给女神写个爱心动画APP】_第1张图片

涉及知识点

本篇文章涉及到技术不多,也都不深,适合各方面技术入门,以下列出关键的一些:

  • Jetpack Compose
  • Compose动画
  • Canvas自由绘制
  • 三次贝塞尔曲线

实现思路

  1. 爱心是左右对称的,所以我们只要能实现半边,另外半边就很容易了

  2. 半边爱心的曲线不算太复杂,但也不简单,使用两段三阶贝塞尔曲线相连才可以达到效果,取样点可以自己草图上画一下,草图可以不用很精确,后续可以根据效果再调整参数,如下
    【情人节用Compose给女神写个爱心动画APP】_第2张图片

  3. 绘制好一边之后,另一边就很简单,数据可以直接拿过来用,注意x轴符号取反就ok了

  4. 用Compose的InfiniteTransition实现大小透明度 的无限循环动画

实现过程

绘制爱心

讲解都在代码注释里了,直接看代码吧

@Composable
fun HeartBeat(
    modifier: Modifier = Modifier.fillMaxSize(),
    color: Color = Color.Red
) {
	Canvas(modifier = modifier) {
        //取canvas当前画布宽高的较小值-30,防止超出边界
        val minSize = min(size.height, size.width) - 30f

        val path = Path()
        //右半边爱心,先移动到中间心窝位置
        path.moveTo(center.x, center.y - minSize / 3)
        //相对位置的三阶贝塞尔曲线,从当前点连接下三个取样点
        path.relativeCubicTo(
            minSize / 4, -minSize / 4,
            minSize / 2, 0f,
            minSize / 2, minSize / 5
        )
        //同理,三阶贝塞尔曲线
        path.relativeCubicTo(
            0f, minSize / 3,
            -minSize * 3 / 8, minSize * 3 / 8,
            -minSize / 2, minSize * 3 / 4
        )

        //左半边爱心,同理,回到心窝位置开始,x轴参数取反即可
        path.moveTo(center.x, center.y - minSize / 3)
        path.relativeCubicTo(
            -minSize / 4, -minSize / 4,
            -minSize / 2, 0f,
            -minSize / 2, minSize / 5
        )
        path.relativeCubicTo(
            0f, minSize / 3,
            minSize * 3 / 8, minSize * 3 / 8,
            minSize / 2, minSize * 3 / 4
        )
        drawPath(path, color)
    }
}

创建动画效果

想要实现心跳的感觉,一个是大小的变化,还有一个就是透明度,由于是无线循环动画,所以使用Compose的InfiniteTransition来实现,不太了解的同学可以后续自行补习一下Compose动画

在HeartBeat方法内,Canvas代码块之上添加如下代码:

@Composable
fun HeartBeat(
    modifier: Modifier = Modifier.fillMaxSize(),
    color: Color = Color.Red,
    duration: Int = 600
) {
	//创建InfiniteTransition
	val transition = rememberInfiniteTransition()
	//使用animateFloat创建透明度动画的State
    val alpha by transition.animateFloat(
        initialValue = 0.3f,
        targetValue = 1f,
        animationSpec = infiniteRepeatable(
            tween(duration),
            repeatMode = RepeatMode.Reverse
        )
    )

	//同理,创建跳动大小动画的State
    val beatSize by transition.animateFloat(
        initialValue = 150f,
        targetValue = 50f,
        animationSpec = infiniteRepeatable(
            tween(duration),
            repeatMode = RepeatMode.Reverse
        )
    )
    
    Canvas(modifier = modifier) {
    //...
    }
}

再改一下原来的Canvas,使用这两个动画参数

//...
Canvas(modifier = modifier) {
	val minSize = min(size.height, size.width) - beatSize
	//...
	drawPath(path, color, alpha)
}

Preview预览效果

这一步早在开发过程中就应该添加了,用Compose的话说:边看边开发,让你更加自信

@Preview
@Composable
fun HeartBeatPre() {
    HeartBeat()
}

至此就已经实现了这么一个简单的心跳动画,附上源码:

完整源码

/*
 * Copyright (c) 2023.
 * @username: LiePy
 * @file: HeartBeat.kt
 * @project: ComposeAnimationKit
 * @model: ComposeAnimationKit.ComposeAnimationKit.main
 * @date: 2023/2/13 下午9:44
 */

package com.lie.composeanimationkit.animation

import androidx.compose.animation.core.*
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.tooling.preview.Preview
import kotlin.math.min

/**
 * @desc 爱心跳动
 * @author LiePy
 * @date 2023/2/13
 */

@Composable
fun HeartBeat(
    modifier: Modifier = Modifier.fillMaxSize(),
    color: Color = Color.Red,
    duration: Int = 600
) {
    val transition = rememberInfiniteTransition()
    val alpha by transition.animateFloat(
        initialValue = 0.3f,
        targetValue = 1f,
        animationSpec = infiniteRepeatable(
            tween(duration),
            repeatMode = RepeatMode.Reverse
        )
    )

    val beatSize by transition.animateFloat(
        initialValue = 150f,
        targetValue = 50f,
        animationSpec = infiniteRepeatable(
            tween(duration),
            repeatMode = RepeatMode.Reverse
        )
    )

    Canvas(modifier = modifier) {
        //最小边作为正方形
        val minSize = min(size.height, size.width) - beatSize

        val path = Path()
        //右半边爱心
        path.moveTo(center.x, center.y - minSize / 3)
        path.relativeCubicTo(
            minSize / 4, -minSize / 4,
            minSize / 2, 0f,
            minSize / 2, minSize / 5
        )
        path.relativeCubicTo(
            0f, minSize / 3,
            -minSize * 3 / 8, minSize * 3 / 8,
            -minSize / 2, minSize * 3 / 4
        )

        //左半边爱心
        path.moveTo(center.x, center.y - minSize / 3)
        path.relativeCubicTo(
            -minSize / 4, -minSize / 4,
            -minSize / 2, 0f,
            -minSize / 2, minSize / 5
        )
        path.relativeCubicTo(
            0f, minSize / 3,
            minSize * 3 / 8, minSize * 3 / 8,
            minSize / 2, minSize * 3 / 4
        )
        drawPath(path, color, alpha)
    }
}

@Preview
@Composable
fun HeartBeatPre() {
    HeartBeat()
}

彩蛋

本动画已收录至我的 git 开源库项目,持续更新中。。。
GitHub: ComposeAnimationKit
Gitee: ComposeAnimationKit

导入使用ComposeAnimationKit,更多好玩的动画等你发现,

implementation 'io.github.LiePy:ComposeAnimationKit:1.1.2' 

你可能感兴趣的:(compose从0开发,android,kotlin,Compose,动画)