https://kotlinlang.org logo
#compose
Title
# compose
m

Mayank Saini

10/27/2020, 8:36 AM
This is my implementation for
Marquee
. Is this correct?
Copy code
@Composable
fun MarqueeText(announcement: String, marqueeSpeed: MarqueeSpeed, modifier: Modifier = Modifier) {
    val scrollState = rememberScrollState()
    val scope = remember { CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) }
    onDispose { scope.cancel() }
    ScrollableRow(scrollState = scrollState, modifier = modifier, children = {
        Row {
            repeat(1000) {
                Text(
                    text = announcement, maxLines = 1
                )
            }
        }
        val scrollBy = when (marqueeSpeed) {
            MarqueeSpeed.SLOW -> 2f
            MarqueeSpeed.MEDIUM -> 6f
            MarqueeSpeed.FAST -> 9f
        }
        scrollState.smoothScrollBy(scrollBy)
        scope.launch {
            while (true) {
                scrollState.smoothScrollBy(scrollBy)
                delay(50)
            }
        }

    })
}
👆 1
@Zach Klippenstein (he/him) [MOD]
z

Zach Klippenstein (he/him) [MOD]

10/27/2020, 4:26 PM
Couple notes: - Never use
remember { CoroutineScope… }
, use
rememberCoroutineScope()
instead. - In this case, you don’t even need that. Never trigger side effects directly in the composition either, use one of the
*Effect
functions. In this case, you could use
LaunchedTask
(which will eventually be renamed to
LaunchedEffect
). - There’s a better way to do looping animations, using animated values (see how cursor blinking is implemented). - I think using
ScrollableRow
here means you’ll have to fight the system to make it non-interactive - better to just use a row and “scroll” it by using modifiers only.
One sec
Actually i’m not sure a row is enough, since you need to measure it as though there’s only a single text. Might need a custom layout.
You can do it with boxes too. Here’s a version with boxes:
And here’s a version with a custom layout.
i think the custom layout one is actually a bit more concise and more readable
Here’s the custom layout one with speed and direction control
m

Mayank Saini

10/28/2020, 10:40 AM
@Zach Klippenstein (he/him) [MOD] Thats a very neat implementation and works as expected. Thanks Zach
z

Zach Klippenstein (he/him) [MOD]

10/28/2020, 1:46 PM
Actually I think that comment is wrong about overflowing the float, I think you need more logic to ensure that doesn't cause visual jitter but anyway the general idea still works.
Also you probably want to measure the children with infinite width, since they're going to be scrolling anyway.
val childConstraints = constraints.copy(maxWidth = Constraints.Infinity)
You could also optimize in the case where the child is wider than the current constraints by not drawing the overflow if it's not within the bounds (by not calling place). If you want to get really fancy, you could use SubcomposeLayout to avoid composing the overflow copy altogether when it's not needed, but unless your scrolling content is very expensive to compose, I don't think it's worth the effort. (Would need to benchmark to show the overhead of subcomposing is less than the overhead of composing twice)
m

Mayank Saini

10/30/2020, 2:03 AM
Is
MarqueeText
in the pipeline as a ready to use feature?
@Zach Klippenstein (he/him) [MOD] The solution works but is consuming ridiculous amount of CPU and energy. What can be the possible solution for this?
z

Zach Klippenstein (he/him) [MOD]

11/02/2020, 4:56 PM
Idk, what does the Android Studio profiler say?
It's only re-positioning the composables on every frame, which I thought was pretty cheap (since the parent size isn't being changed). Might want to try translating the canvas instead though to see if that is any better.
2 Views