Restrict only numbers in TextField in jetpack compose
J

6

17

I want to enter only numbers in Textfield. I tried this stackoverflow logic to restrict alphabet and special characters but when I press dot in my keyboard it's crash.

Error

2022-08-18 09:47:13.966 8050-8050/com.abc.app.dev E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.abc.app.dev, PID: 8050
    java.lang.NumberFormatException: For input string: "."
        at java.lang.Integer.parseInt(Integer.java:733)
        at java.lang.Integer.parseInt(Integer.java:865)
        at com.abc.app.yo.composable.InputKt$InputWithUnitContainer$1$1$1$1.invoke(Input.kt:187)
        at com.abc.app.yo.composable.InputKt$InputWithUnitContainer$1$1$1$1.invoke(Input.kt:186)
        at androidx.compose.foundation.text.BasicTextFieldKt$BasicTextField$7$1.invoke(BasicTextField.kt:266)
        at androidx.compose.foundation.text.BasicTextFieldKt$BasicTextField$7$1.invoke(BasicTextField.kt:264)
        at androidx.compose.foundation.text.CoreTextFieldKt$CoreTextField$onValueChangeWrapper$1.invoke(CoreTextField.kt:241)
        at androidx.compose.foundation.text.CoreTextFieldKt$CoreTextField$onValueChangeWrapper$1.invoke(CoreTextField.kt:236)
        at androidx.compose.foundation.text.TextFieldDelegate$Companion.onEditCommand(TextFieldDelegate.kt:198)
        at androidx.compose.foundation.text.TextFieldDelegate$Companion.access$onEditCommand(TextFieldDelegate.kt:90)
        at androidx.compose.foundation.text.TextFieldDelegate$Companion$restartInput$1.invoke(TextFieldDelegate.kt:246)
        at androidx.compose.foundation.text.TextFieldDelegate$Companion$restartInput$1.invoke(TextFieldDelegate.kt:243)
        at androidx.compose.ui.text.input.TextInputServiceAndroid$createInputConnection$1.onEditCommands(TextInputServiceAndroid.android.kt:111)
        at androidx.compose.ui.text.input.RecordingInputConnection.endBatchEditInternal(RecordingInputConnection.android.kt:162)
        at androidx.compose.ui.text.input.RecordingInputConnection.addEditCommandWithBatch(RecordingInputConnection.android.kt:136)
        at androidx.compose.ui.text.input.RecordingInputConnection.commitText(RecordingInputConnection.android.kt:181)
        at com.android.internal.inputmethod.RemoteInputConnectionImpl.lambda$commitText$16$com-android-internal-inputmethod-RemoteInputConnectionImpl(RemoteInputConnectionImpl.java:569)
        at com.android.internal.inputmethod.RemoteInputConnectionImpl$$ExternalSyntheticLambda34.run(Unknown Source:8)
        at android.os.Handler.handleCallback(Handler.java:942)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loopOnce(Looper.java:201)
        at android.os.Looper.loop(Looper.java:288)
        at android.app.ActivityThread.main(ActivityThread.java:7898)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:936)

Code

appendTextFieldValue: (TextFieldValue) -> Unit,

this is passing through function and below is my Textfield

        TextField(
                value = textFieldValue,
                singleLine = true,
                onValueChange = {
                    if (it.text.length <= maxLength && it.text.toInt() <= maxLength) {
                        appendTextFieldValue(it)
                    }
                    onIsErrorChange(false)
                },
                keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
                isError = isError,
            )
Jaffe answered 18/8, 2022 at 8:55 Comment(4)
Do you want only numbers or also digital number?Comp
@GabrieleMariotti I want numbers like 12345678.... I don't know about digital number. What is difference in numbers and digital number?Jaffe
my bad sorry. number with decimalsComp
I don't need decimals only numbers..Jaffe
C
29

You can use a regex pattern.

Something like:

val pattern = remember { Regex("^\\d+\$") }

TextField(
    value = text,
    onValueChange = {
        if (it.isEmpty() || it.matches(pattern)) {
            text = it
        }
    },
    keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number)
)
Comp answered 18/8, 2022 at 9:38 Comment(5)
one problem occurs when you have one text you cannot use backspace to remove the digit.Jaffe
@vivekmodi Answer updated.Comp
It's possible to modify regex to zero or more digits Regex("^\\d*\$") and you can remove it.isEmpty() from the if condition.Socratic
In fact, after controlling with regex, there is no need to add keyboard Options because we only make changes when the number is entered. Isn't?Mcgovern
@Mcgovern there is , by using KeyboardType.Number only the number keyboard will appear , user can understand the what input is needed also can access the numbers easily if compared to default keyboard.Nadianadine
H
10

This is what I do to achieve this:

TextField(
    value = text,
    onValueChange = { if (it.isDigitsOnly()) text = it },
    keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number)
)
Habit answered 26/7, 2023 at 12:55 Comment(0)
H
4

If you want to show the keyboard with only numbers, simply do this:

TextField(
     value = textState,
     onValueChange = { text ->
         textState = text
     },
     keyboardOptions = KeyboardOptions.Default.copy(
         keyboardType = KeyboardType.NumberPassword
     ),
     visualTransformation = VisualTransformation.None
)
Hawfinch answered 25/3, 2023 at 19:57 Comment(2)
This will not prevent the user from pasting any text they please.Osteology
Agree!. For that we need to validate the text on onValueChange. Something like this we can do. textState = text.filter { txt -> txt.isDigit() }Hawfinch
R
3

You can filter string like`

TextField(
    value = text,
    onValueChange = {
        if (it.isEmpty()) {
            text = it.filter { symbol ->
                symbol.isDigit()
            }
        }
    },
    keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number)
)
Roselynroseman answered 3/2, 2023 at 8:2 Comment(2)
I just want to input positive int number, This is the right way, thanksGregale
This does not work at all because of the it.isEmpty() condition.Osteology
O
1

All the answers using the overload of TextField accepting a String rather than a TextFieldValue are flawed.

The problem with the String overload is that even if we reject the new value, TextField still internally remembers a TextFieldValue and updates its selection property.

For example, if you put the cursor in the middle of the number such as 12|345, and type an illegal character, the cursor will move to the next position like 123|45.


Instead, remember a TextFieldValue and reject the update of the whole TextFieldValue, including the selection property:

var duration by remember { mutableStateOf(TextFieldValue()) }
TextField(
    value = duration,
    onValueChange = {
        if (it.text.all(Char::isDigit)) {
            duration = it
        }
    },
    keyboardOptions = KeyboardOptions(
        keyboardType = KeyboardType.Number,
    ),
)

This way the cursor will not jump move forward even if the user types an illegal character in the middle of the number.

Osteology answered 8/6 at 17:27 Comment(0)
B
0

You can restrict your text field to digits only

var amount by remember { mutableStateOf("") }    
TextField(value = amount, onValueChange = {if (it.isDigitsOnly()) amount = it}
Bonfire answered 1/10, 2023 at 5:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.