I'm trying to implement a Text
view for log-type messages where every change to the text would auto-scroll the Text to the last/newly-added line of text. For example if my text size only fits 4 lines:
log 1
log 2
log 3
log 4
and a new line is added, then the output should be:
log 2
log 3
log 4
log 5
The specific problem I'd like to find a solution for is how to scroll down to the bottom every time there's a change in the text value. I tried the accepted solution for TextField
, where a LaunchedEffect
is triggered during composition phase, but it didn't work in my case:
@Composable
fun LogText(log: State<String>) {
var logState = rememberScrollState(0)
val coroutineScope = rememberCoroutineScope()
LaunchedEffect(coroutineScope) {
logState.scrollTo(logState.maxValue)
}
Text(
text = log.value,
modifier = Modifier.verticalScroll(logState),
)
}
The LaunchedEffect
did not change the Text to scroll down to the newest line.
Your usage of LaunchedEffect
is wrong. The lambda you are passing to the LaunchedEffect
is executed every time the LaunchedEffect
's key(s) are changed. You are using remembered coroutine scope as a key, which never changes, therefore your effect is only executed once.
Also, the LaunchedEffect
lambda is launched in coroutine scope by default, so you don't need your own.
Try it like this:
@Composable
fun LogText(log: State<String>) {
var logState = rememberScrollState(0)
LaunchedEffect(log.value) {
logState.scrollTo(logState.maxValue)
}
...
}
this means: everytime the log.value
changes, execute the lambda.
And one more thing: if your text gets really long, drawing it like that will be quite heavy. I would consider splitting it by lines to List<String>
and using LazyColumn
with multiple Text
items...