Hi all, I am facing one problem in compose where i...
# android
h
Hi all, I am facing one problem in compose where if I change the input text to some format then set it to the field on onValueChange the cursor position is not placed in the right position meaning . I want the cursor position every time at the end of the string . @Composable
Copy code
val textState = mutableStateOf("")
OutlinedTextField(
    value = textState.value,
    onValueChange = {
          textState.value = convertToTSP(it)
        })


fun convertToTSP(val:String){
return (NumberFormat.getNumberInstance(Locale.getDefault()) as DecimalFormat).apply {
            val tsp = "##,###.##"
            applyPattern(tsp)
        }.format(value.toDouble())
}
While doing like this my cursor is not placed at the end of the string every time. Instead it placed around somewhere middle in between the string. I've also tried VisualTransformation for this but It cause one more issue where on tap on anywhere in the textfield my cursor is not moving anywhere other than the end of the text. Is anyone faced these similar issue? Please let if there any ways to solve this issue. Thanks in Advance #compose #android
a
use TextFieldValue instead plain String
Copy code
val fieldValueState = remember { mutableStateOf(TextFieldValue(text = data.initialString, selection = TextRange(data.initialString.length))) }
h
Ok while using TextFieldValue how to change its value onValueChange?
a
onValueChange method has override with TextFieldValue
image.png
h
I am not getting what you're trying to say. Can be more specific?
onValueChange { fieldValueState.value =it } right?
a
++
h
But in my case I want to change the it value before set. So can you pls tell a way to set the formatted text to the TextFieldValue?
a
oh .. Something I missed this moment ;(
This must be done through VisualTransformation/// yes
But TextField Value work for me with VisualTransformation
h
Yes while doing that am facing an issue where if I tap anywhere on the textfield the cursor is not moving anywhere other than end
a
аааа
I can't help you for this issue $(( I havn't had this tasks... sorry
I have same behaviour in my app... realy $#(
h
Can u share ur code how u use textfieldvalue with visual transformation?
a
image.png
this is my textField
nothing special
h
PhoneNumberVisualTransformation us builtin one right?
a
No.. it's my own class
h
Can you share the code for handleInputNumber and PhoneNumberVisualTransformation?
a
Copy code
class PhoneNumberVisualTransformation(formatter: AsYouTypeFormatter) : VisualTransformation {

    private val phoneNumberFormatter = formatter

    override fun filter(text: AnnotatedString): TransformedText {

        val transformation = reformat("+$text", Selection.getSelectionEnd("+$text"))

        val span = buildAnnotatedString {
            val str = transformation.formatted?.replace("+", "") ?: ""
            val firstSpaceIndex = str.indexOfFirst { it == ' ' }
            append(str)
            if (firstSpaceIndex == -1 && str.isNotEmpty() && str.length < 4) {
                addStyle(style = SpanStyle(color = Color(0xff999A9F)), start = 0, str.length)
            } else if (firstSpaceIndex != -1) {
                addStyle(style = SpanStyle(color = Color(0xff999A9F)), start = 0, firstSpaceIndex)
            }
        }

        return TransformedText(span, object : OffsetMapping {
            override fun originalToTransformed(offset: Int): Int {
                return transformation.originalToTransformed.getOrNull(offset) ?: 0
            }

            override fun transformedToOriginal(offset: Int): Int {
                return transformation.transformedToOriginal[offset]
            }
        })
    }

    private fun reformat(s: CharSequence, cursor: Int): Transformation {
        phoneNumberFormatter.clear()

        val curIndex = cursor - 1
        var formatted: String? = null
        var lastNonSeparator = 0.toChar()
        var hasCursor = false

        s.forEachIndexed { index, char ->
            if (PhoneNumberUtils.isNonSeparator(char)) {
                if (lastNonSeparator.code != 0) {
                    formatted = getFormattedNumber(lastNonSeparator, hasCursor)
                    hasCursor = false
                }
                lastNonSeparator = char
            }
            if (index == curIndex) {
                hasCursor = true
            }
        }

        if (lastNonSeparator.code != 0) {
            formatted = getFormattedNumber(lastNonSeparator, hasCursor)
        }
        val originalToTransformed = mutableListOf<Int>()
        val transformedToOriginal = mutableListOf<Int>()
        var specialCharsCount = 0
        formatted?.forEachIndexed { index, char ->
            if (!PhoneNumberUtils.isNonSeparator(char)) {
                specialCharsCount++
            } else {
                originalToTransformed.add(index)
            }
            transformedToOriginal.add(index - specialCharsCount)
        }
        originalToTransformed.add(originalToTransformed.maxOrNull()?.plus(1) ?: 0)
        transformedToOriginal.add(transformedToOriginal.maxOrNull()?.plus(1) ?: 0)

        return Transformation(formatted?.replace("+", ""), originalToTransformed, transformedToOriginal)
    }

    private fun getFormattedNumber(lastNonSeparator: Char, hasCursor: Boolean): String? {
        return if (hasCursor) {
            phoneNumberFormatter.inputDigitAndRememberPosition(lastNonSeparator)
        } else {
            phoneNumberFormatter.inputDigit(lastNonSeparator)
        }
    }

    private data class Transformation(
        val formatted: String?,
        val originalToTransformed: List<Int>,
        val transformedToOriginal: List<Int>
    )
}
h
I'll check and get back Thanks
🤝 1
Can I ask you one more question?. In your case were you able to move the cursor position anywhere on the TextField by tapping or moving?
a
No.. Coursor has only last position
h
Yeah exactly I'm telling this as issue. Because we can't move the cursor anywhere we want right like the native textfield view