How to Create an Animated Strikethrough Text in Jetpack Compose

Kappdev on 2024-02-23

How to Create an Animated Strikethrough Text in Jetpack Compose

Welcome πŸ™‹β€β™‚οΈ

In this article, we’ll create an Animated Strikethrough Text with Jetpack Compose.

This simple yet captivating animation might bring life into your UI.

Especially when combined with checkboxes βœ…

Let’s dive in together πŸš€

Created by Kappdev

Defining the Function

Let’s begin by crafting the AnimatedStrikethroughText composable function:

@Composable
fun AnimatedStrikethroughText(
    text: String,
    modifier: Modifier = Modifier,
    isVisible: Boolean = true,
    animateOnHide: Boolean = true,
    spec: AnimationSpec<Int> = tween(text.length * 30, easing = FastOutLinearInEasing),
    strikethroughStyle: SpanStyle = SpanStyle(),
    textStyle: TextStyle = LocalTextStyle.current
)

Parameters

βœ… text πŸ‘‰ The text to be displayed with the animated strikethrough effect.

βœ… modifier πŸ‘‰ The Modifier to be applied to the Text composable.

βœ… isVisible πŸ‘‰ Determines whether the strikethrough effect should be visible or not.

βœ… animateOnHide πŸ‘‰ Determines whether the animation should be played when hiding the strikethrough effect (isVisible set to false).

βœ… spec πŸ‘‰ Specifies animation specifications. By default, it uses FastOutLinearInEasing, with duration proportional to the text length.

βœ… strikethroughStyle πŸ‘‰ Defines the style of the effect. It allows you to customize the effect and apply not only strikethrough but all the styles supported by SpanStyle.

βœ… textStyle πŸ‘‰ Defines the style of the text. The default value is set to the current local text style.

Implementation

With the function signature defined, let’s proceed to implement the function and bring our animation to life ✨

Utility Function

Before we begin the implementation, let’s encapsulate the logic for building an AnnotatedString into a separate utility function:

fun String.buildStrikethrough(length: Int, style: SpanStyle) = buildAnnotatedString {
    append(this@buildStrikethrough)
    val strikethroughStyle = style.copy(textDecoration = TextDecoration.LineThrough)
    addStyle(strikethroughStyle, 0, length)
}

Defining Variables

To implement the animation, we need to define two variables:

1️⃣ textToDisplay: A mutable state that holds a styled AnnotatedString to be displayed

var textToDisplay by remember { 
    mutableStateOf(AnnotatedString(""))
}

2️⃣ length: An Animatable state that holds the length of the text to be affected

val length = remember { 
    Animatable(initialValue = 0, typeConverter = Int.VectorConverter) 
}

Updating Text Effect

When the length changes, we need to update the textToDisplay variable with the corresponding strikethrough length:

LaunchedEffect(length.value) {
    textToDisplay = text.buildStrikethrough(length.value, strikethroughStyle)
}

Triggering the Animation

When the visibility (isVisible) changes, we initiate the appropriate animation:

LaunchedEffect(isVisible) {
    when {
        isVisible -> length.animateTo(text.length, spec)
        !isVisible && animateOnHide -> length.animateTo(0, spec)
        else -> length.snapTo(0)
    }
}

Updating Text

When the text changes, textToDisplay has to be updated depending on isVisible and the length of the text:

LaunchedEffect(text) {
    when {
        isVisible && text.length == length.value -> {
            textToDisplay = text.buildStrikethrough(length.value, strikethroughStyle)
        }
        isVisible && text.length != length.value -> {
            length.snapTo(text.length)
        }
        else -> textToDisplay = AnnotatedString(text)
    }
}

Rendering the Text

Finally, we have to render the text with the appropriate textToDisplay, modifier, and style:

Text(
    text = textToDisplay,
    modifier = modifier,
    style = textStyle
)

Congratulations πŸ₯³! We’ve successfully built it πŸ‘. You can find the full code on GitHub Gist πŸ§‘β€πŸ’». Let’s explore the usage πŸ‘‡

Practical Usage πŸ’β€β™‚οΈ

For the sake of example, let’s create a list of to-do items featuring checkboxes and the AnimatedStrikethroughText.

First, let’s start by defining the TodoItem component:

@Composable
fun TodoItem(
    text: String,
    checked: Boolean,
    modifier: Modifier = Modifier,
    onCheckedChange: (Boolean) -> Unit
) {
    Row(
        modifier = modifier,
        verticalAlignment = Alignment.CenterVertically
    ) {
        Checkbox(
            checked = checked,
            onCheckedChange = onCheckedChange
        )

        AnimatedStrikethroughText(
            text = text,
            isVisible = checked,
            strikethroughStyle = SpanStyle(
                color = Color.Black.copy(0.32f)
            )
        )
    }
}

Next, let’s define a list of to-do items:

val Tasks = listOf(
    "Grab a coffee",
    "Find a comfy spot",
    "Write some code"
)

The final touch is to place those to-do items into a Column:

Column {
    Tasks.forEach { task ->
        var checked by remember { mutableStateOf(false) }

        TodoItem(
            text = task,
            checked = checked,
            onCheckedChange = {
                checked = it
            }
        )
    }
}

Output πŸ™ˆ

How to Create a Rainbow Loader Animation in Jetpack Compose Welcome πŸ™‹ In this article, we’ll build an amazing Rainbow Loader Animation in Jetpack Compose in less than 5 minutes…medium.com

Thank you for reading this article! ❀️ If you found it enjoyable and valuable, show your appreciation by clapping πŸ‘ and following Kappdev for more exciting articles 😊