Closed Burtan closed 2 weeks ago
What operation system do you have?
Can you please check caret position in this sample: https://github.com/dima-avdeev-jb/compose-check-focus-with-multiline-text It also uses version 1.3.0-beta03
I'm on linux gnome. The sample seems to work, I'll double check my application...
It seems to be related to having the text value being flow based. When I use
val text = remember { mutableStateOf("") }
it works in my app too.
The newest alpha 1.3.0-alpha01-dev862 does not have the problems is also affected.
Please try this:
fun main() = run {
val textFlow = MutableStateFlow("")
application {
Window(
state = WindowState(size = DpSize(350.dp, 500.dp)),
onCloseRequest = ::exitApplication
) {
Column(
modifier = Modifier.padding(50.dp)
) {
for (x in 1..5) {
val textState = textFlow.collectAsState()
val text = remember { textState }
TextField(
value = text.value,
onValueChange = { textFlow.value = it },
label = { Text("Test") },
singleLine = true,
modifier = Modifier.moveFocusOnTab()
.fillMaxWidth()
)
Spacer(Modifier.height(10.dp))
}
}
}
}
}
It work's good on my MacOS
I was wrong it is also buggy on 1.3.0-alpha01-dev862
Windows and Mac work fine. Here is a small clip of the linux behaviour. Bildschirmaufzeichnung vom 2022-11-23, 22-09-48.webm
Also, reproducible on Manjaro Linux
When using a qr code scanner with fast text writing, TextField is also occationally missing some chars on Windows
Any update on this? Will this be fixed? Is it working as intended? The workaround seems to be to only use local states (those created inside the compose function) for textfields.
Unfortunately this is a known issue in the implementation of TextField on Google's side. It's described here: https://medium.com/androiddevelopers/effective-state-management-for-textfield-in-compose-d6e5b070fbe5
We'll have to wait for a fix from Google.
Basing on article, looks like best option for now is creating stateful text field. For me works 🤷 .
@Composable
fun TextFieldStateful(
value: String,
onValueChange: (String) -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
readOnly: Boolean = false,
textStyle: TextStyle = LocalTextStyle.current,
label: @Composable (() -> Unit)? = null,
placeholder: @Composable (() -> Unit)? = null,
leadingIcon: @Composable (() -> Unit)? = null,
trailingIcon: @Composable (() -> Unit)? = null,
isError: Boolean = false,
visualTransformation: VisualTransformation = VisualTransformation.None,
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
keyboardActions: KeyboardActions = KeyboardActions(),
singleLine: Boolean = false,
maxLines: Int = if (singleLine) 1 else Int.MAX_VALUE,
minLines: Int = 1,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
shape: Shape =
MaterialTheme.shapes.small.copy(bottomEnd = ZeroCornerSize, bottomStart = ZeroCornerSize),
colors: TextFieldColors = TextFieldDefaults.textFieldColors()
) {
var state by remember(value) { mutableStateOf(value) }
snapshotFlow { state }
.mapLatest {
onValueChange(it)
}
.stateIn(
scope = rememberCoroutineScope(),
started = SharingStarted.Lazily,
initialValue = state
).collectAsState()
TextField(
value = state,
onValueChange = { newValue ->
state = newValue
},
modifier = modifier,
enabled = enabled,
readOnly = readOnly,
textStyle = textStyle,
label = label,
placeholder = placeholder,
leadingIcon = leadingIcon,
trailingIcon = trailingIcon,
isError = isError,
visualTransformation = visualTransformation,
keyboardOptions = keyboardOptions,
keyboardActions = keyboardActions,
singleLine = singleLine,
maxLines = maxLines,
minLines = minLines,
interactionSource = interactionSource,
shape = shape,
colors = colors
)
}
@mariuszmarzec
You are recreating multiple flows, resubscribing to them and updating state on every recomposition...
Please check the following ticket on YouTrack for follow-ups to this issue. GitHub issues will be closed in the coming weeks.
Hey, I just tried 1.3.0-beta03 from 1.2.1 and realized that writing in a Textfield causes issues on the caret position. After typing e.g. two chars it jumps to the position between the chars instead of staying after the last char.