Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

[Dúvida] (Jetpack Compose)Formatação de entrada double no OutlinedTextField

Olá! primeiramente desculpa caso não seja permitidos tópicos de duvidas de algo fora das aulas, sou novo na plataforma. Estou fazendo um app para portifólio onde será um gestor de finanças. Em um formulário eu tenho um OutilinedTextField que recebe o valor que posteriormente vai ser salvo na base. Até aí tudo bem, porém tenho a seguinte função em uma classe NumberUtil que utilizo para formatar as entradas de numero

 fun formatCurrency(s: String): String {
        var v = digitisOnly(s)

        if (v.isEmpty()) {
            v = "0"
        }

        if (v.length == 1) {
            v = "0,0$v"
        } else if (v.length == 2) {
            v = "0,$v"
        } else {
            val part1 = v.substring(v.length - 2)
            val part2 = v.substring(0, v.length - 2)
            v = "$part2,$part1"
        }

        return v
    }

Em resumo, a função formatCurrency converte a entrada em um formato de valor monetário com uma vírgula para separar os centavos, adicionando zeros à frente dos dígitos conforme necessário.

acontece que ao passar pelo onvaluechange do OutlinedTextField o comportamento não esta funcionando como eu pensei.

supondo que eu digite o valor 150 ele formata corretamente 1,50 entretanto ao precionar o backspace duas vezes o correto seria ficar 0,01 porem ficar 0,05 por o cursor vai para o segundo 0.

alguem faz alguma ideia do motivo disso?

para ter mais contexto esse aqui é o Outlinedtextfied que receberá o valor

 OutlinedTextField(
                    value = if (selectedOption.value == MONETARIO) {
                        mDecimalFormatter.format(currentValueDouble)
                    } else {
                        val formattedValue =
                            mDecimalFormatter.format(currentValuePercent).replace(",", ".")
                        if (isDesconto) {
                            formattedValue.take(5)
                        } else {
                            formattedValue
                        }
                    },
                    onValueChange = { newValue: String ->
                        val formattedValue = newValue.replace(",", ".")

                        if (selectedOption.value == MONETARIO) {
                            currentValueDouble = if (isDesconto) {
                                val newValueDouble = strToDouble(
                                    formatCurrency(formattedValue),
                                    0.0
                                )
                                newValueDouble.coerceIn(
                                    0.0,
                                    totalPedido * 0.99
                                )
                            } else {
                                val newValueDouble = Numbers.strToDouble(
                                    Numbers.formatCurrency(formattedValue),
                                    0.0
                                )
                                newValueDouble
                            }
                        } else {
                            currentValuePercent = if (isDesconto) {
                                val newValueDouble = Numbers.strToDouble(
                                    Numbers.formatCurrency(formattedValue),
                                    0.0
                                )
                                newValueDouble.coerceIn(0.0, 99.0)
                            } else {
                                val newValueDouble = Numbers.strToDouble(
                                    Numbers.formatCurrency(formattedValue),
                                    0.0
                                )
                                newValueDouble
                            }
                        }
                    },
                    colors = TextFieldDefaults.outlinedTextFieldColors(
                        unfocusedBorderColor = AzulEscuro,
                        cursorColor = AzulEscuro,
                        textColor = AzulEscuro
                    ),
                    modifier = Modifier.fillMaxWidth(),
                    keyboardOptions = KeyboardOptions.Default.copy(keyboardType = KeyboardType.Number)
                )
2 respostas
solução!

Olá, Lucas! Não se preocupe, é totalmente válido fazer perguntas fora do conteúdo das aulas, estamos aqui para ajudar!

Pelo que entendi, o problema que você está enfrentando é que a posição do cursor não está sendo atualizada corretamente após a formatação do valor no campo de texto. Isso acontece porque a formatação altera a quantidade de caracteres na string, mas o cursor permanece na mesma posição.

Uma possível solução para isso seria manipular a posição do cursor manualmente. Você poderia criar uma variável para armazenar a posição do cursor e atualizá-la sempre que o valor do campo de texto for alterado.

Vou te dar um exemplo de como fazer isso:

var cursorPosition by remember { mutableStateOf(0) }

OutlinedTextField(
    value = if (selectedOption.value == MONETARIO) {
        mDecimalFormatter.format(currentValueDouble)
    } else {
        val formattedValue =
            mDecimalFormatter.format(currentValuePercent).replace(",", ".")
        if (isDesconto) {
            formattedValue.take(5)
        } else {
            formattedValue
        }
    },
    onValueChange = { newValue: String ->
        val formattedValue = newValue.replace(",", ".")
        cursorPosition = newValue.length // atualiza a posição do cursor

        // ... restante do código

    },
    // ... restante do código
)

Depois, você pode usar essa variável para definir a posição do cursor após a formatação:

val selection = TextRange(cursorPosition)
OutlinedTextField(
    value = TextFieldValue(text = formattedValue, selection = selection),
    // ... restante do código
)

Espero que essa sugestão possa te ajudar a resolver o problema. Lembre-se de testar bem o código para garantir que está funcionando como esperado em todos os casos.

Espero ter ajudado e bons estudos!

Valeu pela ajuda, mesmo que não tenha rolado do jeito que eu queria, pelo menos clareou as ideias pra mim. Depois do que você falou, fui catar informações sobre como o TextFieldValue funciona e acabei bolando uma solução pro meu pepino. Ficou meio grandinho, mas deu pro gasto, haha!

Tive que quebrar a cabeça e reescrever parte do código, mas pelo menos aprendi umas coisas novas nessa jornada. E olha só, até fiz um postzinho no meu LinkedIn sobre como domar o cursor e o foco automático com o OutlinedTextField, caso mais alguém esteja quebrando a cabeça como eu tava.

Quem precisar e quizer dar uma olhada segue o link: https://www.linkedin.com/pulse/melhorando-experi%25C3%25AAncia-do-usu%25C3%25A1rio-com-jetpack-compose-lucas-santana