LoginSignup
3
2

More than 3 years have passed since last update.

[MVVM-DataBinding] 数字入力のEditTextに単位とセパレーターを自動で追加する

Posted at

背景

数字入力に限定したEditText(android:inputType="number")に対して、3桁ごとのセパレーターとsuffixとして単位をつけたい

理由
・ユーザーに極力数字以外のものを受け付けたくない
・桁数と単位でより入力内容をわかりやすくしたい

環境

MVVM-DataBinding
※導入方法は省略

実装

今回は長さ(m)を例に実装します

やりたい事は、もしユーザーが1222と入力したとすると、1,222mEditTextに表示させたいです

XML

snippet.xml
<data>

    <import type="your.package.name.Converter" />

    <variable
        name="viewModel"
        type="your.package.name.SnippetViewModel" />
    </data>

(略)

<EditText
    android:id="@+id/length_m"
    android:layout_width="match_parent"
    android:gravity="end|center_vertical"
    android:hint="0m"
    android:inputType="number"
    android:maxLines="1"
    android:paddingStart="0dp"
    android:paddingEnd="8dp"
    android:text="@={Converter.addNumberSeparatorAndUnitMeter(viewModel.length)}"
    android:textSize="18sp" />

ViewModelbindingvariableとして登録
EditTextの内容を後述するMutableLiveDataと対応させたいので双方向データバインディングしています
Converterimportと使用、こちらも後述

ViewModel

SnippetViewModel.kt
class SnippetViewModel() : ViewModel() {

    val length = MutableLiveData<Int>()

()

ここでは対象のMutableLiveDataを定義しています

Converter

ここではEditText上でユーザーが数字が入力するものの、EditTextには数字+セパレーター+単位を表示したいわけです
ただし、今回は双方向データバインディングのため、またユーザーが数字を入力する際に、EditTextに表示されている数字+セパレーター+単位をそのままgetText等で使い数字のまま使えるわけではないので不整合が生じやすいです

そのため、
・EditTextへの入力内容(Int) -> EditTextの表示内容(String)
・EditTextの表示内容(String) -> EditTextの入力内容(Int)

これらをうまく変換するためのメソッドが必要になります
ここで役立つのが、@InverseMethodです

@InverseMethodでは上記の変換、逆変換をスマートにこなしてくれます
今回の例でいうとこのようになります

Converter.kt
object Converter {
    @InverseMethod("inverseToInt")
    @JvmStatic
    fun addNumberSeparatorAndUnitMeter(value: Int): String {
        val intValueWithFormat = String.format("%,d", value)
        return "${intValueWithFormat}m"
    }

    @JvmStatic
    fun inverseToInt(value: String?): Int {
        return kotlin.runCatching { value?.replace("m", "")?.replace(",", "")?.toInt() }
            .getOrNull() ?: 0
    }
}

ひとつめのaddNumberSeparatorAndUnitMeterではユーザーが入力した内容=LiveDataの値に対してセパレーターとmの単位を付与しています

@InverseMethod("inverseToInt")

inverseToIntは逆変換するのに必要なメソッド名になります
これにより再度ユーザーが数字を入力した際、逆変換のメソッドが呼ばれIntとなり、そのIntの値を使ってまたaddNumberSeparatorAndUnitMeterが呼ばれるということになります

inverseToIntメソッドでは数字+セパレーター+単位をIntに戻しています

これでユーザーが数字を入力するだけでEditTextにセパレーターと単位を補助入力できるようになりました🎉

InverseMethodを使うと何が嬉しいの?

個人的な意見です
・パターンに応じた複雑なロジックを自前で定義する手間が減る
・変換、逆変換の処理を無限ループしにくい状態で定義できる
・もとのLiveDataの値を変換していないままの型(今回はInt)として使うことができるので、その値を使ったバリデーションや値変換(Transformations.map)がしやすい

おわり

以上です 参考になれば幸いです
よりよい方法がありましたら是非ご教授ください🙏

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2