Android DataBinding 〜カスタムビューで使う〜

## はじめに

自作したカスタムビューでDataBindingを使う方法についてまとめます。

## Step0. 準備
今回は、例としてユーザーの名前(name)と年齢(age)を同時に表示するカスタムビューを作ってみます。

### カスタムビュー作成

ユーザー情報は、

```User.java
public class User{
    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }
}
```

で、表示するViewのレイアウトは、

```view_user_info.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable name="user" type="com.example.databindingcustomview.User" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        >
        
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{user.name}"
            />

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{String.valueOf(user.age)}"
            />

        <ProgressBar
            style="@android:style/Widget.Holo.Light.ProgressBar.Horizontal"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:indeterminate="false"
            android:max="100"
            android:progress="@{user.age}"
            />
    </LinearLayout>
</layout>
```

として、Userの情報がTextViewとProgressBarにそれぞれ表示されるようにしてみます。
user.ageはint型なので、```@{String.valueOf(user.age)}```でStringに変換しています。

これをUserInfoViewというカスタムビューのクラスを作ってバインドします。

```UserInfoView.java
public class UserInfoView extends LinearLayout {
    ViewUserInfoBinding mBinding;

    public UserInfoView(Context context){
        super(context);
    }

    public UserInfoView(Context context, AttributeSet attrs) {
        super(context, attrs);

        LayoutInflater inflater = LayoutInflater.from(context);
        mBinding = DataBindingUtil.inflate(inflater, R.layout.view_user_info, this, true);
    }
}
```

### 親レイアウトに配置

これをActivityのレイアウトに組み込みます。

```activity_main.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    >
    <data>
        <variable name="user" type="com.example.databindingcustomview.User" />
    </data>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >
        
        <com.example.databindingcustomview.UserInfoView
            android:id="@+id/user_info"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            />
    </RelativeLayout>
</layout>

```

これでカスタムビューをActivity上に表示するところまでできました。
次にこのビューにUserをセットする方法について説明します。

## Step1. カスタムビュークラスにセッターを用意

まず、UserInfoViewにデータをセットする口を追加し、バインディングと紐付けます。

```UserInfoView.java
public void setUser(User user) {
        mBinding.setUser(user);
}
```

## Step2. BindingAdapterでカスタムセッターを定義

Step1のままでもMainActivity.javaで```user_info.setUser(<User>)```するとUserをセットして表示することができますが、xml上で完結する方法もあります。

BindingAdapterアノテーションを使って独自のカスタムセッターを定義でき、これで好きな属性をxmlから指定できるようになります。
例えば、UserをUserInfoViewにセットするカスタムセッターは、以下のように書きます。

```BindingAdapters.java
@BindingAdapter("user_data")
public static void setUser(UserInfoView view, User user) {
    view.setUser(user);
}
```

書くのはどこでも良いのですが、今回はBindingAdaptersというクラスを用意しました。
これで```user_data```属性が扱えるようになります。

```activity_main.xml
<com.example.databindingcustomview.UserInfoView
    android:id="@+id/user_info"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:user_data="@{user}"
    />
```

名前空間が```android:```ではなく、```app (xmlns:app="http://schemas.android.com/apk/res-auto")```なので注意です。

当然、これは既存のビューにも応用できます。

```BindingAdapters.java
@BindingAdapter("user_data")
public static void setUser(TextView view, User user) {
	//30以上は赤文字
    if (user.getAge() >= 30) {
        view.setTextColor(Color.RED);
    }else{
        view.setTextColor(Color.BLACK);
    }
}
```

```activity_main.xml
<TextView
	...
	app:user_data="@{user}"
	/>
```

## Setp3. データを渡す。

あとは、MainActivity.javaからBindingに対してserUser(<User>)すれば、
カスタムビューにも反映されます。

```binding.setUser(new User("Taro", 6000));```


## おわりに
以上のように、カスタムセッターを使うと独自のカスタムビューや、既存のビューに用意されていないパラメータに対しても自由にデータバインディングできるようになります。