본문 바로가기
Android/Compose UI

[Android] Compose - TextField에 Marked Decimal 숫자 넣기

by Taehyung Kim, dev 2022. 1. 21.
728x90

Android Compose의 숫자를 포맷팅하여 아래와 같은 결과를 만드려고한다 !

 

내가 구현하고 싶은 목표

1. 가장 앞에 원달러 문자가 붙어있어야한다.

2. 숫자를 입력할수록 단위별로 , 문자가 붙는다.

3. 값이 없을경우 항상 0 이 기본값으로 지정된다.

 

위와 같이 만들기 위해서는 TextField의 visualTransformation 값을 지정해야하는데

내가 원하는 기본 제공값은 없어서 VisualTransformation을 구현하기로 하였다.

 

class DecimalMarkedNumberVisualTransformation(
    val prefix: String
) : VisualTransformation {
    override fun filter(text: AnnotatedString): TransformedText {
        val defaultValue = "0"

        val formattedText =
            NumberUtil.convertNumberToDecimalMarkedString(
                text.text
                    .filter { "^[0-9]".toRegex().matches(it.toString()) }
                    .ifEmpty { defaultValue }
                    .toLong()
            )

        val offsetMapping = object : OffsetMapping {
            val initSize = prefix.length + defaultValue.length

            override fun originalToTransformed(offset: Int): Int {
                val commas = formattedText.count { it == ',' }
                return if (offset == 0) initSize else offset + commas + prefix.length
            }

            override fun transformedToOriginal(offset: Int): Int {
                val commas = formattedText.count { it == ',' }
                return offset + commas + prefix.length
            }
        }

        return TransformedText(
            text = AnnotatedString("$prefix$formattedText"),
            offsetMapping = offsetMapping
        )
    }
}

object NumberUtil {

    fun convertNumberToDecimalMarkedString(number: Long): String {
        return NumberFormat.getNumberInstance(Locale.getDefault()).format(number)
    }

}

설명

  • 생성자에 prefix를 넣음으로써 원달러가 아닌 다른 기호도 허용하도록 구현하였다.
    (prefix 뿐 아니라 postfix 등 다양하게 구현이 가능할 것 같다)
  • 기본값을 0으로 지정하여 입력되는 값이 없을 경우에 지정해준다.
  • 입력값을 항상 숫자로 필터링한다.
    (해당 VisualTransformation을 정확한 동작으로 사용하기 위해서 숫자외 다른 문자가 입력되는 것을 막는 방어코드가 필요할 것 같다)
  • 아무것도 입력되지 않았을때 기본 커서의 위치를 잡아주기 위해 initSize 를 지정해준다.

위의 VisualTransformation을 TextField에 파라미터로 넣어주면 위와 같이 동작한다 !

@Composable
fun NumberTextField(
	...
) {
    TextField(
        ...
        visualTransformation = DecimalMarkedNumberVisualTransformation("Some Prefix"),
        ...
    )
}

 

728x90

댓글