CRT Heart
Code
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CutCornerShape
import androidx.compose.material.Icon
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Favorite
import androidx.compose.material.icons.rounded.FavoriteBorder
import androidx.compose.material.icons.rounded.HeartBroken
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.delay
import theme.Colors
import util.lerp
import kotlin.random.Random
import kotlin.time.Duration.Companion.milliseconds
@Composable
fun CRTHeart() {
CRTBox {
Row(
modifier = Modifier
.border(
width = 12.dp,
color = Red500,
shape = CutCornerShape(
bottomEnd = 50.dp,
topStart = 5.dp,
)
)
.padding(24.dp)
.padding(end = 5.dp)
) {
for (i in 1..3) {
HeartIcon(
modifier = Modifier
.size(64.dp)
)
}
}
}
}
@Composable
private fun HeartIcon(modifier: Modifier = Modifier) {
var isBroken by remember { mutableStateOf(false) }
var tintColor by remember { mutableStateOf(Colors.Red500) }
var heartIcon by remember { mutableStateOf(Icons.Rounded.Favorite) }
var offset by remember { mutableStateOf(Offset.Zero) }
LaunchedEffect(isBroken) {
if (isBroken) {
heartIcon = Icons.Rounded.HeartBroken
for (i in 0..50) {
tintColor = listOf(Red500, Colors.Amber300, Colors.Blue200).random()
delay(8.milliseconds)
offset = Offset(Random.nextFloat(), Random.nextFloat())
}
heartIcon = Icons.Rounded.FavoriteBorder
tintColor = Colors.Red800
offset = Offset.Zero
} else {
tintColor = Colors.Red500
heartIcon = Icons.Rounded.Favorite
offset = Offset.Zero
}
}
Icon(
imageVector = heartIcon,
contentDescription = null,
tint = tintColor,
modifier = modifier
.graphicsLayer {
translationX = lerp(-5f, 5f, offset.x)
translationY = lerp(-5f, 5f, offset.y)
}
.clickable(
indication = null,
interactionSource = remember { MutableInteractionSource() }
) {
isBroken = !isBroken
}
)
}The details and code for `CRTBox` can be found in this article: https://www.sinasamaki.com/creating-a-crt-screen-effect-in-jetpack-compose/