Search code examples
androidkotlinandroid-jetpack-composeandroid-jetpack-compose-material3

Getting an IllegalStateException exception with BasicTextField in Jetpack Compose


I have a BasicTextField with a hint. However, for some reason when I put some text in, then delete everything and try to input again, the app crashes. Have no idea how to fix it, any help would be much appreciated :)

I use compose BOM of 2023.04.01, so I believe the issue is not in the version.

My Composable:

@Composable
fun EditableText(
    text: String,
    hint: String,
    onValueChange: (String) -> Unit,
    modifier: Modifier = Modifier
) {

    BasicTextField(
        modifier = modifier,
        value = text,
        onValueChange = onValueChange,
        textStyle = headline.copy(color = Color.White, textAlign = TextAlign.Start),
        singleLine = true,
        decorationBox = { innerTextField ->
            if (text.isEmpty()) {
                Text(
                    textAlign = TextAlign.Start,
                    text = hint,
                    style = headline.copy(
                        color = Color.White.copy(alpha = 0.75f),
                        textAlign = TextAlign.Start
                    )
                )
            } else {
                innerTextField()
            }
        }
    )
}

The error:

FATAL EXCEPTION: main
                                                                                                   Process: com.pm.savings, PID: 7045
                                                                                                    java.lang.IllegalStateException: LayoutCoordinate operations are only valid when isAttached is true
                                                                                                        at androidx.compose.ui.node.NodeCoordinator.localToRoot-MK-Hz9U(NodeCoordinator.kt:881)
                                                                                                        at androidx.compose.foundation.text.TextFieldDelegate$Companion.notifyFocusedRect$foundation_release(TextFieldDelegate.kt:173)
                                                                                                        at androidx.compose.foundation.text.CoreTextFieldKt.notifyFocusedRect(CoreTextField.kt:1077)
                                                                                                        at androidx.compose.foundation.text.CoreTextFieldKt.access$notifyFocusedRect(CoreTextField.kt:1)
                                                                                                        at androidx.compose.foundation.text.CoreTextFieldKt$CoreTextField$5$1$1$2.measure-3p2s80s(CoreTextField.kt:610)
                                                                                                        at androidx.compose.ui.node.InnerNodeCoordinator.measure-BRTryo0(InnerNodeCoordinator.kt:103)
                                                                                                        at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasure$2.invoke(LayoutNodeLayoutDelegate.kt:1090)
                                                                                                        at androidx.compose.ui.node.LayoutNodeLayoutDelegate$performMeasure$2.invoke(LayoutNodeLayoutDelegate.kt:1086)
                                                                                                        at androidx.compose.runtime.snapshots.Snapshot$Companion.observe(Snapshot.kt:2200)
                                                                                                        at androidx.compose.runtime.snapshots.SnapshotStateObserver$observeReads$1$1.invoke(SnapshotStateObserver.kt:234)
                                                                                                        at androidx.compose.runtime.snapshots.SnapshotStateObserver$observeReads$1$1.invoke(SnapshotStateObserver.kt:230)
                                                                                                        at androidx.compose.runtime.SnapshotStateKt__DerivedStateKt.observeDerivedStateRecalculations(DerivedState.kt:341)
                                                                                                        at androidx.compose.runtime.SnapshotStateKt.observeDerivedStateRecalculations(Unknown Source:1)
                                                                                                        at androidx.compose.runtime.snapshots.SnapshotStateObserver.observeReads(SnapshotStateObserver.kt:230)
                                                                                                        at androidx.compose.ui.node.OwnerSnapshotObserver.observeReads$ui_release(OwnerSnapshotObserver.kt:120)

Solution

  • You should return innerTextField even when the text is empty which uses it to set focus, just remove else condition and it should work for both cases

    decorationBox = { innerTextField ->
                if (text.isEmpty()) {
                    Text(
                        textAlign = TextAlign.Start,
                        text = hint,
                        style = headline.copy(
                            color = Color.White.copy(alpha = 0.75f),
                            textAlign = TextAlign.Start
                        )
                    )
                } 
                innerTextField()
            }