Home > Blockchain >  java.lang.NumberFormatException: multiple points with KeyboardType.Decimal
java.lang.NumberFormatException: multiple points with KeyboardType.Decimal

Time:12-15

I'm using KeyboardType.Decimal for the keyboard type in the keyboardOptions entry shown below for an OutlinedTextField, but it's allowing multiple decimals in the typed number. And doing any conversions on such an input like "2.5.8".toDouble() throws a multiple points exception shown below. How can I ensure that only one decimal point is allowed and any subsequent decimal key presses don't do anything?

Composable

CustomOutlinedTextField(
    fieldModifier = Modifier
        .width(100.dp)
        .onFocusChanged {
            if (!it.isFocused) {
                if (mainViewModel.shoppingListItemState.value.quantity == "" || mainViewModel.shoppingListItemState.value.quantity == "0") {
                    mainViewModel.setStateValue(
                        ITEM_QUANTITY_STR,
                        "1"
                    )
                }
            }
        }
        .onPreviewKeyEvent {
            if (it.key == Key.Tab && it.nativeKeyEvent.action == ACTION_DOWN) {
                focusManager.moveFocus(FocusDirection.Right)
                true
            } else {
                false
            }
        },
    label = ITEM_QUANTITY_STR,
    inputVal = mainViewModel.shoppingListItemState.value.quantity,
    isSingleLine = true,
    keyboardOptions = KeyboardOptions.Default.copy(
        capitalization = KeyboardCapitalization.None,
        autoCorrect = false,
        keyboardType = KeyboardType.Decimal,
        imeAction = ImeAction.Next
    ),
    keyboardActions = KeyboardActions(
        onNext = { focusManager.moveFocus(FocusDirection.Right) }
    )
) { value ->
    mainViewModel.setStateValue(ITEM_QUANTITY_STR, value)
}

Exception

 java.lang.NumberFormatException: multiple points

CodePudding user response:

You can check the number of decimalSeparator in the onValueChange of your TextField and allow only one. It is advisable to get the decimalSeparator instead of comparing with . since it might change based on device Locale. Below is a sample implementation of a TextField which checks and allows only one decimalSeparator.

val decimalFormat = DecimalFormat.getInstance(Locale.getDefault()) as DecimalFormat
val decimalSeparator = decimalFormat.decimalFormatSymbols.decimalSeparator

var text by remember { mutableStateOf("123") }

TextField(
    value = text,
    keyboardOptions = KeyboardOptions.Default.copy(
        keyboardType = KeyboardType.Decimal
    ),
    onValueChange = { value ->
        val counter = value.count { it == decimalSeparator }
        if (counter <= 1) { text = value }}
)

CodePudding user response:

You can use a regex in the onValueChange to restrict the allowed character to a decimal number.

Something like:

val pattern = remember { Regex("^\\d*\\.?\\d*\$") }

TextField(
    value = text,
    onValueChange = {
        if (it.isEmpty() || it.matches(pattern)) {
            text = it
        }
    },
    keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Decimal),
)
  • Related