テキストの入力状態でボタンを有効・無効化する

テキストボックスに入力したときだけ押せるボタンを作りたい。
(空のときはdisable、文字があるときはenableにしたい。)

動作例

実装手順

テキストボックスは双方向バインディングでLiveDataと連携されている前提とする。

LiveDataを使用した双方向バインディングについては【Android,Kotlin】双方向・単方向データバインディングの実装手順を参照

MediatorLiveDataで別のLiveDataの変更を監視する

MediatorLiveDataは別のLiveDataの変更にフックして処理を実行できるLiveData
ボタンの状態を保持するLiveDataMediatorLiveDataで定義し、別のLiveDataの変更に連動して値を変更する。

以下のコードではテキストボックスに双方向バインディングされているLiveDataの変更を監視して ボタンの状態を保持するためにMediatorLiveData型でbuttonEnabled変数を定義しておく。

class FirstViewModel : ViewModel() {
    // テキストボックスに双方向バインディングされている LiveData
    val username = MutableLiveData("")

    // 他のLiveDataを監視するためにMediatorLiveDataでボタンの状態を保持する
    val buttonEnabled = MediatorLiveData<Boolean>()

    init {
      // addSourceで連携. usernameが変更されたときに validate() を呼び出す.
       buttonEnabled.addSource(username) { validate() }
    }

    // usernameが変更されたとき、空ならボタンをdisableにする
    private fun validate() {
       buttonEnabled.value = username.value?.isNotEmpty() ?: false
    }
}

初期化時にaddSourceメソッドでusernameを引数に渡すとusernameの変更時にvalidate()が呼び出されるようになる。

もしさらに連携したいLiveDataがある場合は、さらにaddSourceメソッドを呼び出せばよい。

レイアウト: 作成したMediatorLiveDataの値のデータバンディングでボタンをenable/disableする

ボタンに対して単方向バインディング(@{})する。 (レイアウト関連の属性などは省略)

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
  tools:context=".FirstFragment">
  <data>
      <variable
          name="viewModel"
          type="com.example.myapplication.FirstViewModel" />
  </data>
  <androidx.constraintlayout.widget.ConstraintLayout>
    <EditText
        android:id="@+id/username"
        android:text="@={viewModel.username}" />
    <Button
        android:id="@+id/button"
        android:text="@string/next"
        android:enabled="@{viewModel.buttonEnabled}" /> <!-- 単方向バインディング -->
  </androidx.constraintlayout.widget.ConstraintLayout>
</layout>