JetBrains / compose-multiplatform

Compose Multiplatform, a modern UI framework for Kotlin that makes building performant and beautiful user interfaces easy and enjoyable.
https://jetbrains.com/lp/compose-multiplatform
Apache License 2.0
16.24k stars 1.18k forks source link

Text component with UTF-8 emoji text draws very slow (takes seconds) #4222

Closed zoff99 closed 1 month ago

zoff99 commented 9 months ago

Describe the bug

i made an emoji popup:

LazyColumn(
    modifier = Modifier.fillMaxSize().padding(start = 1.dp, end = 10.dp),
    verticalArrangement = Arrangement.spacedBy(5.dp),
    state = listState,
) {
    items(items = emojis_cat_0_gropued) {
        Row(modifier = Modifier.fillMaxWidth().height(40.dp)) {
            for (k in 0..(it.size - 1))
            {
                IconButton(modifier = Modifier.width(40.dp).height(40.dp),
                    onClick = { inputText = inputText + it[k] }) {
                    Text(text = it[k], fontSize = 30.sp, maxLines = 1)
                }
            }
        }
    }
}

sadly its unbearably slow to scroll. if i replace the emoji strings with a normal string like "XX" its super fast. what is going on here? its seems just drawing unicode emoji symbols is unbearably slow

Affected platforms Select one of the platforms below:

Versions

Screenshots If applicable, add screenshots to help explain your problem.

zoff99 commented 9 months ago

emoji popup showing on linux, macos and windows in the lower right corner. when scrolling the box to show more emoji its stuck for 1 second or longer. when replacing all the emoji text with plain "XX" scrolling is super fast like it should be

aaa

mazunin-v-jb commented 9 months ago

Hello! I can't compile this code as is. Could you please create a minimal reproducible example?

zoff99 commented 8 months ago
fun App()
{
    var al: ArrayList<String> = arrayListOf(
        "๐Ÿ˜€","๐Ÿ˜ƒ","๐Ÿ˜„","๐Ÿ˜","๐Ÿ˜†","๐Ÿ˜…",
        "๐Ÿคฃ","๐Ÿ˜‚","๐Ÿ™‚","๐Ÿ™ƒ","๐Ÿซ ","๐Ÿ˜‰",
        "๐Ÿ˜Š","๐Ÿ˜‡","๐Ÿฅฐ","๐Ÿ˜","๐Ÿคฉ","๐Ÿ˜˜",
        "๐Ÿ˜—","โ˜บ๏ธ","๐Ÿ˜š","๐Ÿ˜™","๐Ÿฅฒ","๐Ÿ˜‹",
        "๐Ÿ˜›","๐Ÿ˜œ","๐Ÿคช","๐Ÿ˜","๐Ÿค‘","๐Ÿค—",
        "๐Ÿคญ","๐Ÿซข","๐Ÿซฃ","๐Ÿคซ","๐Ÿค”","๐Ÿซก",
        "๐Ÿค","๐Ÿคจ","๐Ÿ˜","๐Ÿ˜‘","๐Ÿ˜ถ","๐Ÿซฅ",
        "๐Ÿ˜ถโ€๐ŸŒซ๏ธ","๐Ÿ˜","๐Ÿ˜’","๐Ÿ™„","๐Ÿ˜ฌ","๐Ÿ˜ฎโ€๐Ÿ’จ",
        "๐Ÿคฅ","๐Ÿซจ","๐Ÿ˜Œ","๐Ÿ˜”","๐Ÿ˜ช","๐Ÿคค",
        "๐Ÿ˜ด","๐Ÿ˜ท","๐Ÿค’","๐Ÿค•","๐Ÿคข","๐Ÿคฎ",
        "๐Ÿคง","๐Ÿฅต","๐Ÿฅถ","๐Ÿฅด","๐Ÿ˜ต","๐Ÿ˜ตโ€๐Ÿ’ซ",
        "๐Ÿคฏ","๐Ÿค ","๐Ÿฅณ","๐Ÿฅธ","๐Ÿ˜Ž","๐Ÿค“",
        "๐Ÿง","๐Ÿ˜•","๐Ÿซค","๐Ÿ˜Ÿ","๐Ÿ™","โ˜น๏ธ",
        "๐Ÿ˜ฎ","๐Ÿ˜ฏ","๐Ÿ˜ฒ","๐Ÿ˜ณ","๐Ÿฅบ","๐Ÿฅน",
        "๐Ÿ˜ฆ","๐Ÿ˜ง","๐Ÿ˜จ","๐Ÿ˜ฐ","๐Ÿ˜ฅ","๐Ÿ˜ข",
        "๐Ÿ˜ญ","๐Ÿ˜ฑ","๐Ÿ˜–","๐Ÿ˜ฃ","๐Ÿ˜ž","๐Ÿ˜“",
        "๐Ÿ˜ฉ","๐Ÿ˜ซ","๐Ÿฅฑ","๐Ÿ˜ค","๐Ÿ˜ก","๐Ÿ˜ ",
        "๐Ÿคฌ","๐Ÿ˜ˆ","๐Ÿ‘ฟ","๐Ÿ’€","โ˜ ๏ธ","๐Ÿ’ฉ",
        "๐Ÿคก","๐Ÿ‘น","๐Ÿ‘บ","๐Ÿ‘ป","๐Ÿ‘ฝ","๐Ÿ‘พ",
        "๐Ÿค–","๐Ÿ˜บ","๐Ÿ˜ธ","๐Ÿ˜น","๐Ÿ˜ป","๐Ÿ˜ผ",
        "๐Ÿ˜ฝ","๐Ÿ™€","๐Ÿ˜ฟ","๐Ÿ˜พ","๐Ÿ™ˆ","๐Ÿ™‰",
        "๐Ÿ™Š","๐Ÿ’Œ","๐Ÿ’˜","๐Ÿ’","๐Ÿ’–","๐Ÿ’—",
        "๐Ÿ’“","๐Ÿ’ž","๐Ÿ’•","๐Ÿ’Ÿ","โฃ๏ธ","๐Ÿ’”",
        "โค๏ธโ€๐Ÿ”ฅ","โค๏ธโ€๐Ÿฉน","โค๏ธ","๐Ÿฉท","๐Ÿงก","๐Ÿ’›",
        "๐Ÿ’š","๐Ÿ’™","๐Ÿฉต","๐Ÿ’œ","๐ŸคŽ","๐Ÿ–ค",
        "๐Ÿฉถ","๐Ÿค","๐Ÿ’‹","๐Ÿ’ฏ","๐Ÿ’ข","๐Ÿ’ฅ",
        "๐Ÿ’ซ","๐Ÿ’ฆ","๐Ÿ’จ","๐Ÿ•ณ๏ธ","๐Ÿ’ฌ","๐Ÿ‘๏ธโ€๐Ÿ—จ๏ธ",
        "๐Ÿ—จ๏ธ","๐Ÿ—ฏ๏ธ","๐Ÿ’ญ","๐Ÿ’ค","๐Ÿ‘‹","๐Ÿคš",
        "๐Ÿ–๏ธ","โœ‹","๐Ÿ––","๐Ÿซฑ","๐Ÿซฒ","๐Ÿซณ",
        "๐Ÿซด","๐Ÿซท","๐Ÿซธ","๐Ÿ‘Œ","๐ŸคŒ","๐Ÿค",
        "โœŒ๏ธ","๐Ÿคž","๐Ÿซฐ","๐ŸคŸ","๐Ÿค˜","๐Ÿค™",
        "๐Ÿ‘ˆ","๐Ÿ‘‰","๐Ÿ‘†","๐Ÿ–•","๐Ÿ‘‡","โ˜๏ธ",
        "๐Ÿซต","๐Ÿ‘","๐Ÿ‘Ž","โœŠ","๐Ÿ‘Š","๐Ÿค›",
        "๐Ÿคœ","๐Ÿ‘","๐Ÿ™Œ","๐Ÿซถ","๐Ÿ‘","๐Ÿคฒ",
        "๐Ÿค","๐Ÿ™","โœ๏ธ","๐Ÿ’…","๐Ÿคณ","๐Ÿ’ช",
        "๐Ÿฆพ","๐Ÿฆฟ","๐Ÿฆต","๐Ÿฆถ","๐Ÿ‘‚","๐Ÿฆป",
        "๐Ÿ‘ƒ","๐Ÿง ","๐Ÿซ€","๐Ÿซ","๐Ÿฆท","๐Ÿฆด",
        "๐Ÿ‘€","๐Ÿ‘๏ธ","๐Ÿ‘…","๐Ÿ‘„","๐Ÿซฆ","๐Ÿ‘ถ",
        "๐Ÿง’","๐Ÿ‘ฆ","๐Ÿ‘ง","๐Ÿง‘","๐Ÿ‘ฑ","๐Ÿ‘จ",
        "๐Ÿง”","๐Ÿง”โ€โ™‚๏ธ","๐Ÿง”โ€โ™€๏ธ","๐Ÿ‘จโ€๐Ÿฆฐ","๐Ÿ‘จโ€๐Ÿฆฑ","๐Ÿ‘จโ€๐Ÿฆณ",
        "๐Ÿ‘จโ€๐Ÿฆฒ","๐Ÿ‘ฉ","๐Ÿ‘ฉโ€๐Ÿฆฐ","๐Ÿง‘โ€๐Ÿฆฐ","๐Ÿ‘ฉโ€๐Ÿฆฑ","๐Ÿง‘โ€๐Ÿฆฑ",
        "๐Ÿ‘ฉโ€๐Ÿฆณ","๐Ÿง‘โ€๐Ÿฆณ","๐Ÿ‘ฉโ€๐Ÿฆฒ","๐Ÿง‘โ€๐Ÿฆฒ","๐Ÿ‘ฑโ€โ™€๏ธ","๐Ÿ‘ฑโ€โ™‚๏ธ",
        "๐Ÿง“","๐Ÿ‘ด","๐Ÿ‘ต","๐Ÿ™","๐Ÿ™โ€โ™‚๏ธ","๐Ÿ™โ€โ™€๏ธ",
        "๐Ÿ™Ž","๐Ÿ™Žโ€โ™‚๏ธ","๐Ÿ™Žโ€โ™€๏ธ","๐Ÿ™…","๐Ÿ™…โ€โ™‚๏ธ","๐Ÿ™…โ€โ™€๏ธ",
        "๐Ÿ™†","๐Ÿ™†โ€โ™‚๏ธ","๐Ÿ™†โ€โ™€๏ธ","๐Ÿ’","๐Ÿ’โ€โ™‚๏ธ","๐Ÿ’โ€โ™€๏ธ",
        "๐Ÿ™‹","๐Ÿ™‹โ€โ™‚๏ธ","๐Ÿ™‹โ€โ™€๏ธ","๐Ÿง","๐Ÿงโ€โ™‚๏ธ","๐Ÿงโ€โ™€๏ธ",
        "๐Ÿ™‡","๐Ÿ™‡โ€โ™‚๏ธ","๐Ÿ™‡โ€โ™€๏ธ","๐Ÿคฆ","๐Ÿคฆโ€โ™‚๏ธ","๐Ÿคฆโ€โ™€๏ธ",
        "๐Ÿคท","๐Ÿคทโ€โ™‚๏ธ","๐Ÿคทโ€โ™€๏ธ","๐Ÿง‘โ€โš•๏ธ","๐Ÿ‘จโ€โš•๏ธ","๐Ÿ‘ฉโ€โš•๏ธ",
        "๐Ÿง‘โ€๐ŸŽ“","๐Ÿ‘จโ€๐ŸŽ“","๐Ÿ‘ฉโ€๐ŸŽ“","๐Ÿง‘โ€๐Ÿซ","๐Ÿ‘จโ€๐Ÿซ","๐Ÿ‘ฉโ€๐Ÿซ",
        "๐Ÿง‘โ€โš–๏ธ","๐Ÿ‘จโ€โš–๏ธ","๐Ÿ‘ฉโ€โš–๏ธ","๐Ÿง‘โ€๐ŸŒพ","๐Ÿ‘จโ€๐ŸŒพ","๐Ÿ‘ฉโ€๐ŸŒพ",
        "๐Ÿง‘โ€๐Ÿณ","๐Ÿ‘จโ€๐Ÿณ","๐Ÿ‘ฉโ€๐Ÿณ","๐Ÿง‘โ€๐Ÿ”ง","๐Ÿ‘จโ€๐Ÿ”ง","๐Ÿ‘ฉโ€๐Ÿ”ง",
        "๐Ÿง‘โ€๐Ÿญ","๐Ÿ‘จโ€๐Ÿญ","๐Ÿ‘ฉโ€๐Ÿญ","๐Ÿง‘โ€๐Ÿ’ผ","๐Ÿ‘จโ€๐Ÿ’ผ","๐Ÿ‘ฉโ€๐Ÿ’ผ",
        "๐Ÿง‘โ€๐Ÿ”ฌ","๐Ÿ‘จโ€๐Ÿ”ฌ","๐Ÿ‘ฉโ€๐Ÿ”ฌ","๐Ÿง‘โ€๐Ÿ’ป","๐Ÿ‘จโ€๐Ÿ’ป","๐Ÿ‘ฉโ€๐Ÿ’ป",
        "๐Ÿง‘โ€๐ŸŽค","๐Ÿ‘จโ€๐ŸŽค","๐Ÿ‘ฉโ€๐ŸŽค","๐Ÿง‘โ€๐ŸŽจ","๐Ÿ‘จโ€๐ŸŽจ","๐Ÿ‘ฉโ€๐ŸŽจ",
        "๐Ÿง‘โ€โœˆ๏ธ","๐Ÿ‘จโ€โœˆ๏ธ","๐Ÿ‘ฉโ€โœˆ๏ธ","๐Ÿง‘โ€๐Ÿš€","๐Ÿ‘จโ€๐Ÿš€","๐Ÿ‘ฉโ€๐Ÿš€")

    class EmojiStrAndName
    {
        var char: String = ""
        var name: String = ""
    }

    var emojis_cat_all_gropued: java.util.ArrayList<java.util.ArrayList<java.util.ArrayList<EmojiStrAndName>>> = java.util.ArrayList()
    val emojis_cat_gropued: java.util.ArrayList<java.util.ArrayList<EmojiStrAndName>> = java.util.ArrayList()

    val emojis_per_row = 6
    for (i in 0..((al.size - 1) / emojis_per_row))
    {
        val pos = i * emojis_per_row
        val e: java.util.ArrayList<EmojiStrAndName> = java.util.ArrayList()
        for (j in 0..(emojis_per_row - 1))
        {
            val em = EmojiStrAndName()
            try
            {
                em.char = al[pos + j]
                em.name = ""
            }
            catch(_: Exception)
            {
            }
            try
            {
                em.name = "??"
            } catch (_: java.lang.Exception)
            {
            }
            e.add(em)
        }
        emojis_cat_gropued.add(e)
    }
    emojis_cat_all_gropued.add(emojis_cat_gropued)

    Column(Modifier.fillMaxSize().background(Color.White)) {
        val listState = rememberLazyListState()
        Box(Modifier.fillMaxSize()) {
            LazyColumn(
                modifier = Modifier.fillMaxSize().padding(start = 1.dp, end = 10.dp),
                verticalArrangement = Arrangement.spacedBy(5.dp),
                state = listState,
            ) {
                items(items = emojis_cat_all_gropued.get(0)) {
                    Row(modifier = Modifier.fillMaxWidth().height(40.dp)) {
                        println("size="+ it.size)
                        for (k in 0..(it.size - 1))
                        {
                            val emojistr = it[k].char
                            IconButton(modifier = Modifier.width(40.dp).height(40.dp),
                                onClick = {}) {
                                Text(text = emojistr, color = Color.Black, fontSize = 30.sp, maxLines = 1)
                            }
                        }
                    }
                }
            }
            VerticalScrollbar(
                adapter = rememberScrollbarAdapter(listState),
                modifier = Modifier.fillMaxHeight().align(Alignment.CenterEnd).width(10.dp)
            )
        }
    }
}

fun main() = application {
    Window(onCloseRequest = ::exitApplication) {
        App()
    }
}
zoff99 commented 8 months ago

@mazunin-v-jb this code shows that when you drag the scrollbar things totally stop and block. you can not scroll smoothly

zoff99 commented 8 months ago

with this workaround it is a bit better, but still not great:

                        for (k in 0..(it.size - 1))
                        {
                            val emojistr = it[k].char
                            val placeholder = "?"
                            var curtext by remember { mutableStateOf(placeholder) }
                            val scope = rememberCoroutineScope()
                            IconButton(modifier = Modifier.width(40.dp).height(40.dp),
                                onClick = {}) {
                                Text(text = curtext, color = Color.Black, fontSize = 30.sp, maxLines = 1)
                                scope.launch {
                                    delay(150)
                                    curtext = emojistr
                                }
                            }
                        }
okushnikov commented 2 months ago

Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.

zoff99 commented 1 month ago

why are you closing tickets and referring to another platform?