Simple way to make animation character by character ( Kotlin )

Viewed 33

Show letter by letter in an easy way with kotlin Class Like : A An And Andr Andro Androi Android

3 Answers

Try this:

val textView = TextView(this)
val resultText = "Android"
Thread {
    for (i in 0..resultText.length) {
        runOnUiThread { textView.text = resultText.substring(0, i) }
        Thread.sleep(500)
    }
}.start()

You'll have to add textView to some parent, like your contentView.

I like Cactusroot's answer better but here's another way to do it with a Timer

private fun animateCharacters(activity: Activity, str: String, animationIntervalMs: Long) {
    val chars = str.toCharArray().toMutableList()
    var cStr = ""

    val timer = Timer()
    val task = object: TimerTask() {
        override fun run() {
            activity.runOnUiThread {
                val char = chars.removeFirstOrNull()
                if (char == null) {
                    cancel()
                    return@runOnUiThread
                }

                cStr += char
                Log.i("Animated String", cStr)
                // update UI with new text
            }
        }
    }
    timer.schedule(task, 0, animationIntervalMs)
}

There are a couple of issues with the other answers (as of this writing):

  1. It will leak the Activity for the duration of the animation. Suppose the user rotates the screen a few times quickly. There will be many outdated copies of the Activity in memory, still running useless animations.

  2. They assume that all code points fit within a single code unit (Kotlin char). When there are longer code points you will get some weird behavior when you try to set text with the in-between state.

If you do this with a coroutine, it automatically will cancel itself when the activity is destroyed so the activity won't be leaked. This is much simpler than trying to manage threads or timers externally and cancelling them in onDestroy().

To animate text correctly, you should add one code point at a time, not one code unit (Kotlin Char) at a time. This is still assuming there are no emoji in the String. To support emoji is very complicated and you would probably want to use an external library to handle it.

fun typeWrite(textView: TextView, text: String, intervalMs: Long) = lifecycleScope.launch {
    val numCodePoints = text.codePointCount(0, text.length)
    for (i in 0..numCodePoints) {
        textView.text = text.take(text.offsetByCodePoints(0, i))
        delay(intervalMs)
    }
}
Related