Help us understand the problem. What is going on with this article?

独自Viewに双方向DataBinding

More than 1 year has passed since last update.

欲しいなぁと思っていた機能が簡単に実装可能なのでメモ


はじめに

この記事は独自に実装したViewに対して、
EditText.textへの双方向DataBindingのようなものを実装するための方法を記載します

            <EditText
                    ...
                    android:text="@={viewModel.text}" />

これを、こうして双方向DataBindingする方法

            <jp.honkot.CustomizedEditText
                    ...
                    app:text="@={viewModel.text}" />

なお、この例では初歩的なBaseObservableを利用していますが、
ObservableFieldやMutableLiveDataでも代用可能です。

前提

  • DataBindingの利用方法を心得ている
  • 双方向DataBindingの使い方を心得ている

実装イメージ

図にするとこんな感じ

Screen Shot 2019-07-22 at 12.41.04.png

実装

順を追って実装しましょう

Step.1 独自Viewの実装

割愛しますが、まぁこんな感じで書くと思います

CustomizedEditText.kt
class CustomEditText @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
) : ConstraintLayout(context, attrs, defStyleAttr) {
    ...
}

Step.2 InverseBindingMethodsアノテーションを指定

独自ViewクラスにInverseBindingMethodsアノテーションを実装します
このattributeで指定した属性名がそのままXMLファイル上で双方向DataBindingで指定する属性になります

CustomizedEditText.kt
@InverseBindingMethods(
    InverseBindingMethod(
        type = CustomEditText::class,  // 対象のクラス
        attribute = "text"  // 作成する属性
    )
)
class CustomEditText @JvmOverloads constructor(

Step.3 Getter/Setterを用意

指定した双方向DataBindingでやりとりするGetter/Setterを指定
なお、ここではCustomizedEditTextの中でもViewModelが存在し、
その中の属性も双方向DataBindingをしていると仮定する

CustomizedEditText.kt
    fun getText(): String {
        return viewModel.input
    }

    fun setText(value: String) {
        viewModel.input = value
    }

    class ViewModel : BaseObservable() {
        @Bindable
        var input: String = ""
            set(value) {
                field = value
                notifyPropertyChanged(BR.input)
            }
    }

Step.4 InverseBindingListenerを設置

このInverseBindingListenerが、双方向DataBindingで情報をやりとりするインターフェースだと思ってください。
これを独自Viewに持たせる必要があります。この例では独自ViewのViewModelに持たせます

CustomizedEditText.kt
    fun setInverseBindingListener(listener: InverseBindingListener) {
        viewModel.listener = listener
    }

    class ViewModel : BaseObservable() {
        @Bindable
        var input: String = ""
            set(value) {
                field = value
                listener?.onChange() // ここ、重要
                notifyPropertyChanged(BR.input)
            }

        var listener: InverseBindingListener? = null
    }

Step.5 BindingAdapterを作成

XMLに記載するためのBindingAdapterを作成
このアノテーションで定義することで、指定Viewに対するXML上での拡張属性を作成可能

CustomizedEditText.kt
    object CustomEditTextBindingAdapter {
        @BindingAdapter("textAttrChanged") // 属性名+AttrChanged
        @JvmStatic
        fun setTextWatcher(view: CustomEditText?, listener: InverseBindingListener) {
            view?.setInverseBindingListener(listener)
        }
    }

Step.6 拡張Viewに対して双方向DataBindingを指定

MainActivity.kt
    private val binding: ActivityMainBinding by lazy {
        DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding.viewModel = viewModel
    }

    class ViewModel : BaseObservable() {
        @Bindable
        var textWatcher: String = ""
            set(value) {
                field = value
                notifyPropertyChanged(BR.textWatcher)
            }
    }
activity_main.xml
            <jp.honkot.CustomEditText
                    ...
                    app:text="@={viewModel.textWatcher}"/>

こうすると、常に独自Viewの値を監視できます。

SYABU555
GooglePlayにてアプリを公開中。 日々の技術的なことはこちらに残すそうかと画策中。 ■オートマナー https://play.google.com/store/apps/details?id=jp.chau2chaun2.mannerstimer ■QuickSleep https://play.google.com/store/apps/details?id=jp.ch
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away