Laggy keyboard after first keystroke in TextField Jetpack Compose

112 Views Asked by At

I am experiencing lags after first keystroke and then everything works smoothly. It happens both in debug and release(with minification)

Below is AppInputText composable:

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun AppInputText(
    modifier: Modifier = Modifier,
    valueProvider: () -> String,
    onValueChange: (String) -> Unit,
    labelText: String = "ilość",
    labelTextStyle: TextStyle = MaterialTheme.typography.labelMedium.copy(
        fontFamily = FontFamily(Font(R.font.open_sans_extrabold)),
    ),
    isSuffixEnabled: Boolean = false,
    inputTextStyle: TextStyle = MaterialTheme.typography.titleLarge.copy(
        lineHeight = 22.sp,
        fontWeight = FontWeight.Bold,
        color = Color(0xFF495A81).copy(alpha = 0.78f),
        textAlign = if (isSuffixEnabled) TextAlign.End else TextAlign.Start,
    ),
    registerQuantity: () -> Unit = {},
    isEnabled: Boolean = true,
    isReadOnly: Boolean = false,
    keyboardType: KeyboardType = KeyboardType.Number,
    amount: Int = 1,
    placeholderText: String = "Zeskanuj albo wpisz…",
) {
    val interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }
    val singleLine = true
    val colors = OutlinedTextFieldDefaults.colors(
        focusedBorderColor = Color(0xFF667396),
        unfocusedBorderColor = Color(0xFF8892AC),
        focusedLabelColor = Color(0xFF8892AC),
        unfocusedLabelColor = Color(0xFF8892AC),
        focusedContainerColor = Color.White,
        unfocusedContainerColor = Color.White,
        errorContainerColor = Color.White,
        disabledContainerColor = Color.White,
        focusedTextColor = Color(0xFF495A81).copy(alpha = 0.78f),
        unfocusedTextColor = Color(0xFF495A81).copy(alpha = 0.78f),
        unfocusedTrailingIconColor = Color(0xFF495A81).copy(alpha = 0.6f),
        focusedTrailingIconColor = Color(0xFF495A81).copy(alpha = 0.6f),
    )
    val focusRequester = remember { FocusRequester() }
    val focusManager = LocalFocusManager.current
    val trailingIconText = @Composable {
        Icon(
            modifier = Modifier
                .clip(CircleShape)
                .clickable {
                    onValueChange("")
                    focusRequester.requestFocus()
                }
                .requiredSize(34.dp)
                .padding(5.dp)
                .background(
                    color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f),
                    shape = CircleShape
                )
                .padding(4.dp),
            imageVector = Icons.Filled.Close,
            tint = MaterialTheme.colorScheme.surface.copy(alpha = 0.87f),
            contentDescription = "clear icon"
        )
    }

    BasicTextField(
        value = valueProvider(),
        onValueChange = onValueChange,
        modifier = modifier
            .defaultMinSize(minHeight = 52.dp)
            .focusRequester(focusRequester),
        interactionSource = interactionSource,
        enabled = isEnabled,
        readOnly = isReadOnly,
        singleLine = singleLine,
        textStyle = inputTextStyle,
        keyboardOptions = KeyboardOptions(
            imeAction = if (valueProvider().isNotBlank()) ImeAction.Done else ImeAction.Send,
            keyboardType = keyboardType,
        ),
        keyboardActions = KeyboardActions(
            onDone = {
                defaultKeyboardAction(ImeAction.Done)
                focusManager.clearFocus()
                registerQuantity()
            }
        )
    ) { basicTextField ->
        OutlinedTextFieldDefaults.DecorationBox(
            isError = valueProvider().isBlank(),
            placeholder = {
                if (valueProvider().isBlank()) {
                    Text(
                        modifier = Modifier.padding(vertical = 6.dp),
                        text = placeholderText,
                        style = MaterialTheme.typography.labelMedium.copy(
                            fontSize = 16.sp,
                            fontFamily = FontFamily(Font(R.font.lato_light)),
                            color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.46f),
                        )
                    )
                }
            },
            value = valueProvider(),
            visualTransformation = VisualTransformation.None,
            innerTextField = basicTextField,
            label = {
                Text(
                    text = labelText.uppercase(),
                    style = labelTextStyle
                )
            },
            singleLine = singleLine,
            enabled = isEnabled,
            suffix = {
                if (isSuffixEnabled) {
                    Row {
                        Text(
                            text = " z $amount",
                            textAlign = TextAlign.Start,
                            style = MaterialTheme.typography.titleLarge.copy(
                                lineHeight = 22.sp,
                                fontWeight = FontWeight.Bold,
                                color = Color(0xFF495A81).copy(alpha = 0.78f),
                            ),
                        )
                        Spacer(modifier = Modifier.fillMaxWidth(0.8f))
                    }
                }
            },
            trailingIcon = if (valueProvider().isNotBlank() && !isReadOnly) trailingIconText else null,
            interactionSource = interactionSource,
            contentPadding = OutlinedTextFieldDefaults.contentPadding(
                top = 8.dp, bottom = 8.dp
            ),
            colors = colors,
            container = {
                OutlinedTextFieldDefaults.ContainerBox(
                    enabled = isEnabled,
                    isError = valueProvider().isBlank(),
                    colors = colors,
                    interactionSource = interactionSource,
                    shape = RoundedCornerShape(11.dp),
                    unfocusedBorderThickness = 1.33.dp,
                    focusedBorderThickness = 2.dp
                )
            },
        )
    }
}

Through valueProvider I pass text state and through onValueChange state is being updated through events, viewModels etc. I've tried using derivedStateOf, but it didn't resolve this issue.

I suppose the issue might be that at first, when the TextField is empty, it has red borders, it has text below TextField etc and then it changes which might cause more recompositions than needed, but I can't spot the issue.

Additionaly, I can open the keyboard only once. If I try to open it twice, it doesn't work.

No text TextField TextField with text

1

There are 1 best solutions below

0
Name On

You are probably using the beta version. I encountered this problem in the beta version of implementation. Same performance problems and like you said: "Additionaly, I can open the keyboard only once. If I try to open it twice, it doesn't work."

implementation 'androidx.compose.material3:material3:1.2.0-beta01'.

Best to stick with an older alpha version like this until it's fixed.

implementation 'androidx.compose.material3:material3:1.2.0-alpha11'