1

我正在尝试实现一个 TextField,它输入一个数量并在键入后立即对其进行格式化,并将其限制为 100,000。

@Composable
fun MainScreen(
    viewModel: MyViewModel
) {
    val uiState by viewModel.uiState.collectAsState()
    Column {
        AmountSection(
            uiState.amount,
            viewModel::updateAmount
        )
        Text(text = viewModel.logs)
    }
}

@Composable
fun AmountSection(
    amount: TextFieldValue,
    updateAmount: (TextFieldValue) -> Unit
) {
    BasicTextField(
        value = amount,
        onValueChange = updateAmount,
        keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number
    )
)

我的视图模型:

class MyViewModel: ViewModel() {

    private val _uiState = MutableStateFlow(MyUiState())
    val uiState: StateFlow<MyUiState> = _uiState

    var logs by mutableStateOf("")
    var text = ""

    fun updateAmount(amount: TextFieldValue) {
        val formattedAmount: String = amount.text.getFormattedAmount()
        text += "input = ${amount.text}\n"
        text += "output = $formattedAmount \n"
        logs = text
        _uiState.update {
            it.copy(amount = TextFieldValue(formattedAmount, TextRange(formattedAmount.length))
        }
    }    
}

data class MyUiState(val amount: TextFieldValue = TextFieldValue())

logs并且text仅用于记录目的。发现很难共享 logcat 输出,因此以这种方式呈现)

结果:

在此处输入图像描述

  • 当我按 6 时,输入是预期的“12,3456”(忽略货币)
  • 我的getFormattedAmount()函数将最后六个删除为(123456 > 100000)。它输出“12,345”,这也是正确的。“12,345”是屏幕上显示的内容。
  • 但是当我按 7 时,我得到输入“12,34567”。那个6是哪里来的??它不在uiState.amount

(请忽略最后一个输出行。getFormattedAmount仅在数量超过限制时删除最后一个字符,并且它给出了错误的输出,因为它没有预料到该输入)

我觉得我在这里犯了一些非常愚蠢的错误,如果有人能帮助我找出答案,我将非常感激。

4

2 回答 2

0

根据编辑进行编辑:-从问题的外观来看,您希望在这里实现什么并不太清楚,但这是我的推论-您只需要一个允许输入数字的 TextField,但最多只能输入一个最大值(VALUE,不是字符)。当用户按数字导致值超过您的最大值时,您当然希望不输入该数字,但您希望在这种情况下完全不反映任何变化,即字段值应保持不变。

基于上述推论,这里有一个例子:-

首先,你的 uiState 变量。为了清楚起见,我保持简单。

class VM: ViewModel(){
 var fieldValue by mutableStateOf("")
 
 fun onFieldUpdate(newValue){
   if(newValue.toDouble() > 999999999999999)
   return
   else
   fieldValue = newValue
 }
}

@Composable
fun CrazyField(fieldValue: String, onFieldUpdate: (String) -> Unit){
 TextField(value = fieldValue, onValueChange = onFieldUpdate)
}

不要在没有实际运行的情况下进一步评论。

原始答案:- 使用双精度解析器。

var text by remember { mutableStateOf("") }
TextField(
    value = text,
    onValueChange = {
        if (it.toDouble() <= 100000)
            text = it //Based on your use-case - it won't cut off text or limit the amount of characters
       else text = it.subString(0,7) //In-case of pasting or fast typing
    },
    keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number)
)
于 2021-10-31T10:00:03.243 回答
0

在 Sean 的 Compose slack 频道上找到了这条评论。

作为模型,您应该假设键盘可以对每个onValueChange. 例如,如果用户使用自动更正、用表情符号替换单词或其他智能编辑功能,则可能会发生这种情况。要正确处理此问题,请编写任何转换逻辑,假设当前传递给的文本与将传递给onValueChange的上一个或下一个值无关onValueChange

所以这是 TextField 和 IME 关系的一些问题。
我重写了我的getFormattedAmount函数以在没有任何假设的情况下格式化给定的字符串(之前假设金额被格式化到最后第二个字符)。现在一切似乎都已解决。

于 2021-11-01T12:22:23.303 回答