Hello guys, I'm trying to improve my app regarding...
# compose
s
Hello guys, I'm trying to improve my app regarding accessibility and keyboard usage. According to the documentation a composable with
verticalScroll
modifier should be scrollable with PgUp/PgDown keys by default but it's not working for me, even for a simple example app. What am I doing wrong? (Code snippet in thread)
Copy code
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
    val scrollState = rememberScrollState()
    val interactionSource = remember { MutableInteractionSource() }

    Column(
        modifier = Modifier
            .padding(innerPadding)
            .indication(interactionSource = interactionSource, indication = LocalIndication.current)
            .focusable(interactionSource = interactionSource)
            .verticalScroll(scrollState)
    ) {
        Text("Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.")
        Text("Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.")
        Text("Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.")
        Text("Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.")
        Text("Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.")
    }
}
Compose BOM
2025.03.01
Kotlin
2.1.20
Android emulator with API 35
n
import androidx.compose.foundation.LocalIndication import androidx.compose.foundation.focusable import androidx.compose.foundation.indication import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.verticalScroll import androidx.compose.material.Scaffold // Assuming Material 2 // import androidx.compose.material3.Scaffold // Or Material 3 import androidx.compose.material.Text // Assuming Material 2 // import androidx.compose.material3.Text // Or Material 3 import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester // Import this specifically @Composable fun ScrollableScreen() { // Wrap in a Composable function if not already Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding -> val scrollState = rememberScrollState() val interactionSource = remember { MutableInteractionSource() } val focusRequester = remember { FocusRequester() } // 1. Create a FocusRequester Column( modifier = Modifier .padding(innerPadding) .focusRequester(focusRequester) // 2. Attach the FocusRequester // Optional: Keep indication for visual feedback when focused .indication(interactionSource = interactionSource, indication = LocalIndication.current) // Make it focusable (needed for focusRequester and keyboard input) .focusable(interactionSource = interactionSource) // Apply scrolling .verticalScroll(scrollState) // Ensure the Column can fill space if needed, otherwise scrolling might not activate .fillMaxSize() // Added this - important if the content might not exceed parent bounds initially ) { Text("Lorem ipsum dolor sit amet...") // Your long text content Text("Lorem ipsum dolor sit amet...") Text("Lorem ipsum dolor sit amet...") Text("Lorem ipsum dolor sit amet...") Text("Lorem ipsum dolor sit amet...") } // 3. Request focus when the composable enters the composition LaunchedEffect(Unit) { focusRequester.requestFocus() } } }
use this code
s
Why do I need a
FocusRequester
? Shouldn't it work when I focus the element via keyboard?
n
I didn't understand you query
s
Is that AI generated code? 🤔
😬 1
yes black 2
🤣 7
Interestingly, when adding an
onKeyEvent
modifier and logging the key code, I get valid codes for all keys pressed except PgUp and PgDown, which are
0
?! Additionally tried to use a
LazyColumn
(of course without the
verticalScroll
modifier) but there scrolling with PgUp / PgDown is also not working. I'm confused to say the least.
😕 1
So, scrolling via PgUp/PgDown keys works in a Compose Multiplatform desktop app 🤯 Thanks @Mike Penz for testing / confirming this. It seems this is an Android issue. Is there no one here with more insights?
m
Do you get expected keycodes from your keyboard's PgUp/PgDown keys in general, such as in
onKeyDown()
in an activity?
s
Good point! This code in the
Activity
outputs
0
for both PgUp and PgDown keys just like in Compose. So it doesn't seem to be a Compose issue 🤔
Copy code
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
    Log.d("KEY", "${event?.keyCode}")
    return super.onKeyDown(keyCode, event)
}