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),
)
