【Kotlin】AndroidのTextWatcherでViewを引数で取得できないの困るよねって話

# TextWatcherでViewを引数で取得したい

Androidでボタンをクリックした時などにコールバックを受け取るリスナーって
たいていの場合、どのViewのイベントかを判別できるようにViewのインスタンスを取得できる仕様になってると思います。
### OnClickListenerの場合

```kotlin

override fun onClick(view: View?) {
        when(view){
            hoge1Button -> {
                //処理
            }
            hoge2Button -> {
                //処理
            }
        }
    }

```

まさに上のような感じ。
引数にViewが入ってくるので、どのViewなのかで条件分岐してあげてそれぞれに処理を書くことができます。とても便利ですね。

しかし

なぜか、EditTextの文字列を取得するTextWatcherでは、それができない。

### TextWatcherの場合

```kotlin

    override fun afterTextChanged(p0: Editable?) {
        //処理
    }

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

    override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
        //処理
    }

```

引数にViewが入ってこない・・・。なんなんだこの仕様は・・・。

正直なところ、EditTextが一つだけならあまり問題にならないのですが
Activity内にEditTextが複数存在し、それぞれに処理を書かないといけないとなると

```kotlin

 hoge1EditText.addTextChangedListener(object : TextWatcher{
            override fun afterTextChanged(p0: Editable?) {
                //処理
            }

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

            override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
                //処理
            }
        })

hoge2EditText.addTextChangedListener(object : TextWatcher{
            override fun afterTextChanged(p0: Editable?) {
                //処理
            }

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

            override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
                //処理
            }
        })

hoge3EditText.addTextChangedListener(object : TextWatcher{
            override fun afterTextChanged(p0: Editable?) {
                //処理
            }

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

            override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
                //処理
            }
        })

...

```

このような感じで、EditTextごとにTextWatherを実装してやらなきゃいけないので、めちゃくちゃソースが膨れ上がります。冗長で読みづらくなり保守性も下がっていきます。

そこで、何とかしてこいつらをまとめられるように、Viewを引数に取れる実装にできないか考えてみました。

まず、Viewを引数に取れるメソッドを定義した独自のinterfaceを作ります。
今回はとりあえずCustomTextWatcherListenerと命名しています。

```kotlin

interface CustomTextWatcherListener {
    fun afterTextChanged(view: View, p0: Editable?)

    fun beforeTextChanged(view: View, p0: CharSequence?, p1: Int, p2: Int, p3: Int)

    fun onTextChanged(view: View, p0: CharSequence?, p1: Int, p2: Int, p3: Int)
}

```

次に、TextWatcherを実装したクラスを定義します。
コンストラクタでViewとCustomTextWatcherListenerを渡せるように実装しましょう。
クラスの名前は適当にCustomTextWatcherで

```kotlin

class CustomTextWatcher(val view: View, val listener: CustomTextWatcherListener): TextWatcher {

    override fun afterTextChanged(p0: Editable?) {
        listener.afterTextChanged(view, p0) //上で作成したリスナーに処理を渡す
    }

    override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
        listener.beforeTextChanged(view, p0, p1, p2, p3) //上で作成したリスナーに処理を渡す
    }

    override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
        listener.onTextChanged(view, p0, p1, p2, p3) //上で作成したリスナーに処理を渡す
    }

}

```

最後に、上で定義したクラスとインターフェースを使って
Activity内に実装していきましょう。


```kotlin

class HogeActivity : Activity(), CustomTextWatcherListener {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_hoge)

        hoge1EditText.apply { addTextChangedListener(CustomTextWatcher(this, this@HogeActivity)) }
        hoge2EditText.apply { addTextChangedListener(CustomTextWatcher(this, this@HogeActivity)) }
        hoge3EditText.apply { addTextChangedListener(CustomTextWatcher(this, this@HogeActivity)) }

    }

    override fun afterTextChanged(view: View, p0: Editable?) {
        when(view){
            hoge1EditText -> {
                //処理
            }
            hoge2EditText -> {
                //処理
            }
            hoge3EditText -> {
                //処理
            }
        }
    }

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

    }

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

    }
}

```
TextWatcherでViewを含んだコールバックを受け取れるようになりました。

EditTextの数が多くなればなるほどこの実装は便利になるので、ぜひ活用してみてください。

間違っている箇所や、より良い実装がありましたらご指摘いただけると幸いです。