Search code examples
kotlinandroid-jetpack-compose

Jetpack Compose large BasicTextField is not resizing correctly when the keyboard is active


I am trying to create a text editor for Android in Jetpack Compose, but for several days I keep struggling with this very annoying behaviour of the BasicTextField (also tried with TextField): whenever I try to type into the text field, the field is shrunk to a pretty low height, does not follow the cursor when I type and it doesn't go to the line that i clicked on.

On a physical device it's even worse because the text field is not even visible (I also tried it with a smaller keyboard size and while a part of the field became visible, it still wasn't behaving properly). This is my code:

MainActivity.kt

@Composable
fun MainContent() {
    Scaffold(
        modifier = Modifier.fillMaxSize()
    }
    ) { innerPadding ->
        Surface(
            modifier = Modifier
                .consumeWindowInsets(innerPadding) //this makes the bottom bar visible
                .padding(innerPadding)
                .imePadding()
        ) {
            TextEditor(sb.toString()) //sb is a StringBuilder, it's that long text
        }
    }
}

TextEditor.kt

@Composable
fun TextEditor(text: String) {

...

Column(modifier = Modifier.fillMaxSize()) {
        BasicTextField(
            state,
            onValueChange = {
                state = it
            },
            modifier =
            Modifier
                .weight(1f)
                .horizontalScroll(rememberScrollState())
                .verticalScroll(rememberScrollState())
                .fillMaxWidth()
                .padding(10.dp, 0.dp, 10.dp, 0.dp),
            textStyle =
            LocalTextStyle.current.copy(
                color = MaterialTheme.colorScheme.onSurface,
                fontSize = 20.sp
            ),
            cursorBrush = Brush.linearGradient(
                colors = List(2) {
                    MaterialTheme.colorScheme.secondary
                    MaterialTheme.colorScheme.secondary
                })
        )


        Row(modifier = Modifier.background(MaterialTheme.colorScheme.secondary)) {
            Text(
                "Ln: $currentLine, Col: $currentColumn",
                color = MaterialTheme.colorScheme.onSecondary
            )
            Spacer(modifier = Modifier.weight(1f))
            Text(
                "UTF-8",
                color = MaterialTheme.colorScheme.onSecondary
            )
            Spacer(modifier = Modifier.width(10.dp))
            Text(
                "LF",
                color = MaterialTheme.colorScheme.onSecondary
            )
        }
    }

The app in the normal state The app in input mode

I have set android:windowSoftInputMode="adjustResize" in the manifest, I've also tried with adjustPan, I've added the field in another column, a row, setting focus with FocusRequester, literally nothing works. It's so annoying when the framework fights back when you try to do something a bit uncommon, like a text editor, as I've tried to force it to not adjust anything when the keyboard is shown, as that would have been ideal in this case.

Is this the wrong approach implementing a text editor? I also tried to use TextField for the currently edited row only, while for the other ones to have a Text, but the problem is that it makes text selection difficult, as the Text elements would be selected (using SelectionContainer, but the TextField won't). I'm not trying to create something very complex, so I thought a text field would be good, but it seems it doesn't work that easily.

EDIT: After some measurements with a screen ruler, it seems that the padding added to the top when the keyboard is shown is almost equal with the keyboard's height. I tried to use some offsets, to counteract this, but so far I've not succeeded. Is this the intended behaviour of Compose (to add padding to both top and bottom) or is it just a bug?


Solution

  • So I basically solved it by not having a top bar in the Scaffold component. If anyone stumbles upon this issue, just try to remove your topBar from the Scaffold.

    P.S. In the original code, you don't see a topBar because I removed the code that I thought was unnecessary, in this case the top bar and the bottom bar. Who knew that the top bar was the culprit? This is most likely a Compose bug. Anyway, I hope anyone that finds this exact issue will be able to solve it with this workaround.