Jetpack Создает курсор установки в конце текстового поля

#android #textfield #phone-number #android-jetpack-compose #cursor-position

Вопрос:

Хочу создать текстовое поле для номера телефона. Нужна помощь с установкой курсора в поле всегда в конце строки

Что я пытаюсь сделать: когда в поле появляется новое число , я получаю все уже введенные числа, затем добавляю подчеркивание( _ ) для длины строки не менее 11, а затем возвращаю строку с числами или «_» подстрокой:

return " 7(${template.substring(1, 4)}) ${template.substring(4,7)} ${template.substring(7,9)} ${template.substring(9, 11)}" Если курсор всегда в конце, это работает, но если нет, порядок чисел нарушен

Полный код:

@Составная

 @Composable
fun PhoneNumberEditText(
    phoneNumState: MutableState<String>,
    modifier: Modifier = Modifier,
    imeAction: ImeAction = ImeAction.Done,
    onImeAction: () -> Unit = {}
) {
    TextField(
        shape = RoundedCornerShape(16.dp),
        value = phoneNumState.value,
        onValueChange = { value ->
            phoneNumState.value = value
            val digits = phoneNumState.value.toCharArray().filter { it.isDigit() }
            phoneNumState.value = phoneNumTemplate(digits)
        },
        modifier = modifier
            .clip(RoundedCornerShape(16.dp))
            .size(343.dp, 54.dp),
        singleLine = true,
        placeholder = {
            Text(
                " 7(___)_______", style = passwordTextStyle,
            )
        },
        colors = TextFieldDefaults.textFieldColors(
            backgroundColor = whiteBackground,
            focusedIndicatorColor = Color.Transparent,
            unfocusedIndicatorColor = Color.Transparent,
            cursorColor = greyColor,
            textColor = greyColor
        ),
        leadingIcon = {
            Image(
                painterResource(id = R.drawable.ic_phone),
                stringResource(id = R.string.nomad_contentDescription_icon_phone)
            )
        },
        keyboardOptions = KeyboardOptions(
            imeAction = imeAction,
            keyboardType = KeyboardType.Phone
        ),
    )

}
 
 

Устройство для смены струн:

 fun phoneNumTemplate(chars: List<Char>): String {
    return if (chars.isNotEmpty()) {
        val digits = mutableListOf<Int>()
        chars.forEach {
            digits.add(it.toString().toInt())
        }
        val template = StringBuilder()
        digits.forEach { template.append(it) }
        for (i in 0..11) {
            template.append("_")
        }
        " 7(${template.substring(1, 4)}) ${template.substring(4,7)} ${template.substring(7,9)} ${template.substring(9, 11)}"
    } else {
        " 7(___) ___ __ __"
    }
}

 

спасибо вам за вашу помощь

Ответ №1:

Это что-то другое, но вместо использования onValueChange вы можете попробовать использовать visualTransformation свойство.
Что-то вроде:

 TextField(
    //your code...,
    visualTransformation = PhoneNumberTransformation()

)
 

с:

 class PhoneNumberTransformation() : VisualTransformation {
    override fun filter(text: AnnotatedString): TransformedText {
        return phoneNumFilter(text)
    }
}

fun phoneNumFilter(text: AnnotatedString): TransformedText {

    //  X(XXX)_XXX_XX_XX
    val trimmed = if (text.text.length >= 11) text.text.substring(0..10) else text.text
    var out = ""
    for (i in trimmed.indices) {
        if (i==0) out  = " "
        if (i==1) out  = "("
        out  = trimmed[i]
        if (i==3) out  =") "
        if (i==6 || i==8 ) out  = " "
       
    }
    
    val phoneNumberOffsetTranslator = object : OffsetMapping {
        override fun originalToTransformed(offset: Int): Int {
            if (offset <= 0) return offset
            if (offset <= 1) return offset  1
            if (offset <= 3) return offset  2
            if (offset <= 7) return offset  4
            if (offset <= 9) return offset  5
            if (offset <= 11) return offset  6
            return 17
            
        }

        override fun transformedToOriginal(offset: Int): Int {
            if (offset <=0) return offset
            if (offset <=2) return offset -1
            if (offset <=7) return offset -2
            if (offset <=12) return offset -4
            if (offset <=15) return offset -5
            if (offset <=18) return offset -6
            return 11
        }
    }

    return TransformedText(AnnotatedString(out), phoneNumberOffsetTranslator)
}
 

введите описание изображения здесь