androidandroid-jetpack-composeandroid-jetpack-compose-textandroid-compose-textfield

How to create a text field input with mask in jetpack compose?


I need a text field in jetpack compose that works with a mask like this: NNNNN-NNN where N is an integer from 0 to 9. I need my composable function to have this mask in the OutlinedTextField :

@Composable
private fun EditTextField(
    labelText: String,
    value: String,
    keyboardType: KeyboardType = KeyboardType.Text,
    onValueChanged: (String) -> Unit
) {
    OutlinedTextField(
        modifier = Modifier.padding(top = 8.dp),
        label = { Text(text = labelText) },
        keyboardOptions = KeyboardOptions(keyboardType = keyboardType),
        value = value,
        onValueChange = onValueChanged
    )
}

Solution

  • You can use the visualTransformation property:

    OutlinedTextField(
        value = text,
        onValueChange = { it ->
            text = it.filter { it.isDigit() }
        },
        keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Number),
        visualTransformation = MaskTransformation()
    )
    

    with:

    class MaskTransformation() : VisualTransformation {
        override fun filter(text: AnnotatedString): TransformedText {
            return maskFilter(text)
        }
    }
    
    
    fun maskFilter(text: AnnotatedString): TransformedText {
    
        // NNNNN-NNN
        val trimmed = if (text.text.length >= 8) text.text.substring(0..7) else text.text
        var out = ""
        for (i in trimmed.indices) {
            out += trimmed[i]
            if (i==4) out += "-"
        }
    
        val numberOffsetTranslator = object : OffsetMapping {
            override fun originalToTransformed(offset: Int): Int {
                if (offset <= 4) return offset
                if (offset <= 8) return offset +1
                return 9
    
            }
    
            override fun transformedToOriginal(offset: Int): Int {
                if (offset <=5) return offset
                if (offset <=9) return offset -1
                return 8
            }
        }
    
        return TransformedText(AnnotatedString(out), numberOffsetTranslator)
    }
    

    enter image description here