Skip to content

Instantly share code, notes, and snippets.

fun getPathCanvasObject() = CanvasPath(
path = Path().apply {
heartPath(Size(120f, 120f))
},
)
fun getTextCanvasObject(text: String = "hi") =
CanvasText(text) {
color = android.graphics.Color.WHITE
isAntiAlias = true
const val G = -9.8f
// we are sending one item to the producerChannel at a time
val xVelocity = Random.nextInt(-50, 50)
val yVelocity = 100 // Random.nextInt(0, 200)
return ItemStateBuilder(
composeCanvasDrawItem = getTextCanvasObject("\uD83D\uDD25"),
initialX = width / 2,
initialY = (height - 500f),
Canvas(modifier = modifier,
onDraw = {
for (item in items) {
translate(top = item.y, left = item.x) {
drawContext.canvas.nativeCanvas.apply {
when (val itemToDraw = item.itemToDraw) {
is CanvasPath -> {
scale(
scale = item.scale,
pivot = Offset(
// we are sending one item to the producerChannel at a time
ItemStateBuilder(
composeCanvasDrawItem = getPathCanvasObject(),
initialX = Random.nextInt(0, (width).toInt()).toFloat(),
initialY = (height - 200f),
)
.animateX(
to = {
initialX
producerChannel.trySend(
List(10) {
getItemCircleLoader(width, height, (it * 100))
}
)
fun getItemCircleLoader(width: Float, height: Float, initialDelay: Int = 0) =
ItemStateBuilder(
composeCanvasDrawItem = getTextCanvasObject(),
initialX = (width / 2 - 400f),
fun ItemStateBuilder.build(): ItemState
fun ItemStateBuilder.animateY(
to: ItemStateBuilder.() -> Float,
animationSpec: ItemStateBuilder.() -> AnimationSpec<Float>,
): ItemStateBuilder
fun ItemStateBuilder.animateY(
to: ItemStateBuilder.() -> Float,
animationSpec: ItemStateBuilder.() -> AnimationSpec<Float>,
): ItemStateBuilder
fun ItemStateBuilder.animateX(
class ItemStateBuilder(
val composeCanvasDrawItem: ComposeCanvasDrawItem,
val initialX: Float,
val initialY: Float,
val initialAlpha: Float = 1.0f,
val initialAngle: Float = 0.0f,
val initialColor: Color = Color.White,
val initialScale: Float = 1.0f
) {
internal var xAnimation: Animation<Float, AnimationVector1D>? = null
data class ItemState constructor(
val id: String = UUID.randomUUID().toString(),
val x: Float,
val y: Float,
val alpha: Float,
val scale: Float,
val angle: Float,
val color: Color,
val xAnimation: Animation<Float, AnimationVector1D>,
val yAnimation: Animation<Float, AnimationVector1D>,
val itemsToAnimate = remember {
mutableStateOf<List<ItemState>>(mutableListOf())
}
val itemsChannel = remember {
Channel<List<ItemState>>(Channel.UNLIMITED)
}
var job: Job? = remember {
null
}
val producerChannel = remember {
Channel<List<ItemState>>(Channel.UNLIMITED)
}
LaunchedEffect(true) {
for (incomingList in producerChannel) {
launch(Dispatchers.IO) {
itemsChannel.trySend(itemsToAnimate.value.toMutableList().apply {
addAll(incomingList)
})