1import android.text.InputType
2
3// Integer only
4editText.inputType = InputType.TYPE_CLASS_NUMBER
5
6// Decimal
7editText.inputType = InputType.TYPE_CLASS_NUMBER or InputType.TYPE_NUMBER_FLAG_DECIMAL
8
9// Signed decimal
10editText.inputType = InputType.TYPE_CLASS_NUMBER or
11 InputType.TYPE_NUMBER_FLAG_DECIMAL or
12 InputType.TYPE_NUMBER_FLAG_SIGNED
13
14// Phone
15editText.inputType = InputType.TYPE_CLASS_PHONE
1// Integer only
2editText.setInputType(InputType.TYPE_CLASS_NUMBER);
3
4// Decimal
5editText.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL);
6
7// Signed decimal
8editText.setInputType(InputType.TYPE_CLASS_NUMBER
9| InputType.TYPE_NUMBER_FLAG_DECIMAL | InputType.TYPE_NUMBER_FLAG_SIGNED); ``` ## Using digits Attribute ```xml <!-- Only allow specific characters --> <EditText android:id="@+id/etPIN" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="number" android:digits="0123456789" android:maxLength="4" android:hint="Enter 4-digit PIN" /> <!-- Only allow hex digits --> <EditText android:id="@+id/etHex" android:layout_width="match_parent" android:layout_height="wrap_content" android:digits="0123456789ABCDEFabcdef" android:hint="Enter hex value" /> ``` `android:digits` restricts input to the specified characters only. Characters not in the string are silently rejected. ## InputFilter for Custom Validation ```kotlin import android.text.InputFilter // Limit to a range (e.g., 1-100) class MinMaxFilter(private val min: Int, private val max: Int) : InputFilter { override fun filter( source: CharSequence, start: Int, end: Int, dest: android.text.Spanned, dstart: Int, dend: Int ): CharSequence? { try { val input = (dest.toString() + source.toString()).toInt() if (input in min..max) return null // Accept } catch (e: NumberFormatException) { // Reject } return "" // Reject the input } } // Apply the filter editText.filters = arrayOf(MinMaxFilter(1, 100)) // Combine with max length filter editText.filters = arrayOf( MinMaxFilter(1, 100), InputFilter.LengthFilter(3) ) ``` ## TextWatcher for Real-Time Validation ```kotlin import android.text.TextWatcher import android.text.Editable editText.addTextChangedListener(object : TextWatcher { override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {} override fun afterTextChanged(s: Editable?) { val text = s?.toString() ?: return if (text.isEmpty()) return try { val value = text.toDouble() if (value > 999.99) { editText.error = "Maximum value is 999.99" } } catch (e: NumberFormatException) { editText.error = "Invalid number" } } }) ``` `TextWatcher` provides real-time feedback without blocking input. Use `editText.error` to show inline error messages. ## Jetpack Compose ```kotlin import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.material3.TextField import androidx.compose.runtime.* import androidx.compose.ui.text.input.KeyboardType @Composable fun NumericTextField() { var text by remember { mutableStateOf("") } TextField( value = text, onValueChange = { newValue -> // Filter to digits only text = newValue.filter { it.isDigit() } }, label = { Text("Enter number") }, keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Number ) ) } // Decimal input @Composable fun DecimalTextField() { var text by remember { mutableStateOf("") } TextField( value = text, onValueChange = { newValue -> // Allow digits and one decimal point if (newValue.isEmpty() || newValue.matches(Regex("^\\d*\\.?\\d*$"))) { text = newValue } }, keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Decimal ) ) } ``` In Compose, `KeyboardType.Number` shows the numeric keyboard, and `onValueChange` filters invalid characters. ## Common Pitfalls * **inputType does not prevent paste**: Users can paste non-numeric text from the clipboard even with `inputType="number"`. Use an `InputFilter` or `TextWatcher` to validate pasted content. * **numberDecimal allows multiple decimal points on some keyboards**: Some third-party keyboards do not enforce single decimal point. Validate in `afterTextChanged` or `onValueChange` to reject multiple dots. * **Forgetting numberSigned for negative values**: `inputType="number"` only allows positive digits. If negative numbers are valid (temperature, coordinates), add `numberSigned` to the input type. * **maxLength not applying to programmatic setText**: `android:maxLength` only limits user input. Calling `setText()` in code ignores the limit. Validate in code as well if you set text programmatically. * **Keyboard type vs input validation**: `inputType` controls the keyboard shown and provides basic filtering, but it is not a security measure. Always validate the final value before processing — never trust client-side input alone. ## Summary * Use `android:inputType="number"` in XML for integer-only input with numeric keyboard * Add `numberDecimal` and `numberSigned` flags for decimal and negative numbers * Use `android:digits` to restrict to a specific set of allowed characters * Use `InputFilter` for range validation and `TextWatcher` for real-time feedback * In Jetpack Compose, combine `KeyboardType.Number` with `onValueChange` filtering * Always validate the final value server-side — `inputType` is a UI hint, not a security measure