48
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Android DataBinding + Kotlin でつまずいたこと(BindingAdapter多め)

Last updated at Posted at 2018-04-04

はじめに

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

例えば、 EditTextViewandroid:onTextChanged を使いたい場合、TextViewBindingAdapter.java にすでに BindingAdapter があるのでそれを使うことができます。

ここに BindingMethod の記述もあるので、 set**Listener のようなメソッド BindingMethod をわざわざ用意しなくてもよくなるかもしれません。

引数に Context を使いたい

DataBinding で、Context を引数に持つメソッドを使いたいとき、以下の記事を参照しました。
context とそのまま渡せば動作するんだ。

DataBindingで引数にcontextを渡すメソッドを扱う

48
31
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
48
31

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?