はじめに
DataBinding を使っていて、つまずいた点とそれを解消した方法を書いていきます。(半分は備忘録)
カスタムセッター(BindingAdapter アノテーション)を作ったときのTips多めです。
Kotlin で BindingAdapterのエラー
Javaでカスタムセッターを作るとこんな感じで書けました。
@BindingAdapter("imageUrl")
public static void loadImage(ImageView view, String url) {
// do something
}
始めに、Kotlinでカスタムセッターをこう書きました。
class ImageViewBindingAdapter {
companion object {
@BindingAdapter("imageUrl")
@JvmStatic
fun loadImage(view: ImageView, imageUrl: String) {
// do something
}
}
}
DataBindingAttribute.Companion is not static and requires an object to use, retrieved from the DataBindingComponent.
companion object
を使って、staticメソッドする方法では、上記のエラーとなってしまう。
下記の方法でカスタムセッターを書くといけます。
object ImageViewBindingAdapter {
@BindingAdapter("imageUrl")
@JvmStatic
fun loadImage(view: ImageView, imageUrl: String) {
// do something
}
}
Kotlinの拡張関数を使うこともできます。
object ImageViewBindingAdapter {
@BindingAdapter("imageUrl")
@JvmStatic
fun ImageView.loadImage(imageUrl: String) {
// do something
}
}
XMLは、JavaとKotlinともに同じです。
<ImageView
app:imageUrl="@{viewModel.imageUrl}" />
Kotlin でカスタムセッターに複数のパラメータ指定
Javaだとこんな感じで書けました。
@BindingAdapter({"imageUrl", "error"})
public static void loadImage(ImageView view, String url, Drawable error) {
// do something
}
Kotlinだとこうです。
object ImageViewBindingAdapter {
@BindingAdapter("imageUrl", "error")
@JvmStatic
fun ImageView.loadImage(imageUrl: String, error: Drawable) {
// do something
}
}
XMLではこう書きます。
<ImageView
app:imageUrl="@{viewModel.imageUrl}"
app:error="@{@drawable/errorImage}" />
以下のように、一部のパラメータしか指定していなかった場合うまく動きません。
<ImageView
app:imageUrl="@{viewModel.imageUrl}" />
これは BindingAdapterの requireAll
属性がデフォルトで true
になっているためです。
この場合、すべてのパラメータが指定されていないと呼ばれません。
一部のパラメータでも呼ばれるようにするには、BindingAdapter を以下のように書き換えます。
@BindingAdapter("imageUrl", "error", requireAll = false)
BindingAdapter に Int, Boolean を渡したい
BindingAdapter に Int をセットしたくて、以下のように書いたがうまく動かなかった。
object ImageViewBindingAdapter {
@BindingAdapter("imageUrl", "position")
@JvmStatic
fun ImageView.loadImage(imageUrl: String, position: Int) {
// do something
}
}
<ImageView
app:imageUrl="@{viewModel.imageUrl}"
app:position="1" />
原因は XML での書き方にあり、以下のように変えると動きます。
<ImageView
app:imageUrl="@{viewModel.imageUrl}"
app:position="@{1}" />
Boolean を渡したい場合はこう書く。
<ImageView
app:imageUrl="@{viewModel.imageUrl}"
app:dispflag="@{true}" />
なぜこう書かないといけないのかわかっていないので、知っている方がいたら教えてください。
BindingAdapter に リソース ID を渡したい
以下のように、Rクラスを import すればいけます。
<data>
<import type="com.sample.R"/>
<variable
name="viewModel"
type="com.sample.TestViewModel" />
</data>
<ImageView
app:src="@{viewModel.resourceId ?: R.drawable.error}" />
android:onClick 以外のイベントを処理したい
まず、標準で用意されている Adapter が存在するか確認しました。
https://android.googlesource.com/platform/frameworks/data-binding/+/master/extensions/baseAdapters/src/main/java/android/databinding/adapters
例えば、 EditTextView
の android:onTextChanged
を使いたい場合、TextViewBindingAdapter.java にすでに BindingAdapter があるのでそれを使うことができます。
ここに BindingMethod の記述もあるので、 set**Listener のようなメソッド BindingMethod をわざわざ用意しなくてもよくなるかもしれません。
引数に Context を使いたい
DataBinding で、Context を引数に持つメソッドを使いたいとき、以下の記事を参照しました。
context
とそのまま渡せば動作するんだ。