EditText 화폐 단위(원, 세자리 씩 끊어 쉼표) 실시간 반영

이지훈·2022년 2월 8일
2

앱을 사용하는 도중 금액을 입력받는 상황은 자주 발생한다.
토스로 친구에게 송금을 한다던지 등등

그런 상황에서 inputType이 number 일때 어떻게 1,000,000 과 같은 쉼표를,
커서 맨 뒤에 '원' 이라는 글자를 붙힐 수 있는지 알아보자

P.S 쉼표를 찍는 법은 구글링을 통해 쉽게 검색이 되는데, 뒤에 '원'이라는 글자를 붙히는 방법은
잘 나오지 않아 누군가가 이 글을 보고 도움을 받지 않을까 해서 작성한다.

우선 쉼표를 붙혀주는 방법은 구글링을 통해 쉽게 검색을 할 수 있다.
(블로그 주인님 감사합니다. 덕분에 편하게 구현하였습니다)
https://kiwinam.com/posts/17/android-edittext-comma/

자바로 되어있는 코드이지만, 코틀린으로 쉽게 변환할 수 있기 때문에 변환해서 사용하면 된다.
문제는 원이다.

처음으로 시도했던 방법은 위에 코드에서

TextWatcher watcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

}

@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
    if(!TextUtils.isEmpty(charSequence.toString()) && !charSequence.toString().equals(result)){
        result = decimalFormat.format(Double.parseDouble(charSequence.toString().replaceAll(",","")));
        wonEt.setText(result);
        wonEt.setSelection(result.length());
    }
}

@Override
public void afterTextChanged(Editable editable) {

}
};

result라는 결과에 '원'을 맨 뒤에 붙혀 edittext의 text 로 붙히고 다시 텍스트를 입력하려할때 droplast(1) 과 같은 확장함수를 이용해서 뺐다 붙혔다 하는 방법이었는데 원하는 결과를 얻지 못하였다. (가능은 할 것 같은데 outofindex 에러와 type casting 에러 발생위험이 클 것 같아서 방법을 우회하였다.

내가 해결한 방법은 edittext 위에 textview를 겹치게 위치해둔 다음 (INVISIBLE상태로) TextWatcher를 이용해서 edittext에 값이 변화하면(빈값 -> 입력값) textview의 text를 edittext의 text값(금액) + '원'으로 넣어주고 VISIBLE 상태로 변경해주는 방법이다.

text 값이 없다면(썼다가 다 지우면) textview에 해당 작업을 해주지 않고 다시 보이지 않도록 INVISIBLE 처리를 해주면 된다.

xml

<EditText
                android:id="@+id/et_register_lesson_price"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginHorizontal="16dp"
                android:layout_marginTop="8dp"
                android:background="@drawable/bg_register_rounded_edit_text_gray"
                android:hint="@string/enter_lesson_price"
                android:inputType="number"
                android:maxLength="9"
                android:paddingHorizontal="18dp"
                android:visibility="visible"
                android:textSize="16dp"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/tv_register_lesson_price" />

            <TextView
                android:id="@+id/tv_register_lesson_price_Info"
                android:textColor="@color/black"
                android:visibility="invisible"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginHorizontal="16dp"
                android:layout_marginTop="8dp"
                android:background="@drawable/bg_register_rounded_edit_text_gray"
                android:gravity="center_vertical"
                android:paddingHorizontal="18dp"
                android:textSize="16dp"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/tv_register_lesson_price" />

code

    private fun validateInputForm(editText: EditText, button: AppCompatButton) = with(binding) {
        var result = ""
        val decimalFormat = DecimalFormat("#,###")

        editText.addTextChangedListener(object : TextWatcher {
            @RequiresApi(Build.VERSION_CODES.M)
            override fun beforeTextChanged(charSequence: CharSequence?, i1: Int, i2: Int, i3: Int) {
            }

            override fun onTextChanged(charSequence: CharSequence?, i1: Int, i2: Int, i3: Int) {
                if (!TextUtils.isEmpty(charSequence!!.toString()) && charSequence.toString() != result) {
                    lessonPrice = charSequence.toString().replace(",", "").toInt()
                    result =
                        decimalFormat.format(charSequence.toString().replace(",", "").toDouble())
                    editText.setText(result)
                    tvRegisterLessonPriceInfo.apply {
                        text = getString(R.string.input_lesson_price, result)
                        visibility = View.VISIBLE
                    }

                    editText.setSelection(result.length)
                }

                if (TextUtils.isEmpty(charSequence.toString()) && charSequence.toString() != result) {
                    result = ""
                    editText.setText(result)
                    tvRegisterLessonPriceInfo.apply {
                        text = result
                        visibility = View.INVISIBLE
                    }
                }
            }

			// 이 밑으론 해당 글과는 딱히 관련 없는 코드로 무시해도 된다. 
            @RequiresApi(Build.VERSION_CODES.M)
            override fun afterTextChanged(editable: Editable?) {
                if (editable.isNullOrEmpty()) {
                    (activity as RegisterLessonActivity).lockButton(button)
                } else {
                    (activity as RegisterLessonActivity).unlockButton(button)
                }
            }
        })

        editText.setOnFocusChangeListener { _, gainFocus ->
            if (gainFocus) {
                editText.setBackgroundResource(R.drawable.bg_register_rounded_edit_text_sloth)
            } else {
                editText.setBackgroundResource(R.drawable.bg_register_rounded_edit_text_gray)
            }
        }
    }

strings.xml

 <string name="input_lesson_price">%1$s원</string>

edittext와 textview에서 숫자+, 는 중복으로 쓰여지고
textview에만 맨 뒤에 '원'을 붙히며
edittext의 커서를 맨뒤로 보내 항상 '원'이라는 글자 바로 앞으로 나오도록 구현하였다.
(두 view에 중복적으로 글자가 작성되는게 약간 꺼려져 textview에만 글자가 쓰이도록 해보려했는데
그러면 커서의 위치가 '원'바로 앞으로 오지 않았다. 더 나은 방법이 있으면 알려주시면 감사)

실행 화면

profile
실력은 고통의 총합이다. Android Developer

0개의 댓글