Simple&Natural

BindingAdapter 를 이용하여 EditText 에 양방향 바인딩 사용하기 본문

안드로이드(Android)

BindingAdapter 를 이용하여 EditText 에 양방향 바인딩 사용하기

Essense 2023. 1. 5. 15:37
728x90

DataBinding과 LiveData를 사용하면 여러모로 편리한 점이 많다.

 

하지만 실제 뷰모델에서 사용하는 데이터와 자료형이 다른 경우가 생긴다. 

예를 들면, 잔액을 표시하는 경우 

 

보통 뷰모델에서는 

val amount: LiveData<Int> = ...

와 같은 형식으로 정의되어 있는데

 

이를 TextView나 EditText에 보여줄 때는 문자열 타입이 필요하기 때문이다.

 

양방향 바인딩을 사용하는 경우 이럴 때 어떻게 해야 할지 참 난감해진다.

 

그럴 땐 BindingAdapter를 사용하면 된다.

 

/**
 * LiveData 에서는 숫자(Int, Long, BigInteger...) 타입을 유지하고
 * EditText 에 표시할 때는 문자열 타입으로 표시해주기 위해 사용함.
 * BindingAdapter 를 사용하면 Comma 를 사용하는 양방향 데이터 바인딩이 가능함.
 *
 * **/
@BindingAdapter("textWithComma")
fun EditText.textWithComma(num: Any?): String {
    return when (num) {
        is Int -> DecimalFormat("###,###").format(num)
        is Long -> DecimalFormat("###,###").format(num)
        is BigInteger -> DecimalFormat("###,###").format(num)
        else -> ""
    }.also {
        if (text.toString() != it) {
            setText(it)

            // 양방향 바인딩 사용 시 문자열 입력/삭제 시 커서가 처음으로 이동하는 문제가 있음.
            // 문자열 입력/제거 시 항상 마지막 커서로 이동시켜주기 위해 사용함.
            setSelection(it.length)
        }
        Logger.d("textWithComma >> $it")
    }
}

@InverseBindingAdapter(attribute = "textWithComma", event = "textAttrChanged")
fun EditText.getTextString(): Int {
    return (text.toString().replace(",", "").toIntOrNull() ?: 0).also { Logger.d("textAttrChanged >> $it") }
}

@BindingAdapter("textAttrChanged")
fun EditText.setTextWatcher(textAttrChanged: InverseBindingListener){
    addTextChangedListener(object : TextWatcher {
        override fun afterTextChanged(p0: Editable?) { textAttrChanged.onChange() }

        override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { }

        override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {

        }
    })
}

@BindingAdapter("textWithComma")
fun TextView.textWithComma(num: Any?): String {
    return when (num) {
        is Int -> DecimalFormat("###,###").format(num)
        is Long -> DecimalFormat("###,###").format(num)
        is BigInteger -> DecimalFormat("###,###").format(num)
        else -> ""
    }.also {
        text = it
        Logger.d("TextView.textWithComma >> type is ${num?.javaClass?.simpleName}, value is $it")
    }
}

직접 만들어 사용하고 있는 함수들이다.

 

 

728x90