［Android］ Include タグを利用したときに Databinding する方法

# はじめに

Android では Layout の再利用性を高められるよう Include タグを利用すれば、
作成済みの Layout ファイルを他の Layout ファイルに埋め込むことができます。

**作成済みの Layout ファイル**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79387/ffbbb4d8-bb00-8c88-f6b5-8c28aedcf092.png)

```xml:one_fragment.xml
    <FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="Good Sample"
            android:textSize="32sp"
            />
    </FrameLayout>
```


**他の Layout ファイルを埋め込んだ Layout ファイル**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79387/5a2276af-752c-9b6c-6da3-a52ee1a4f041.png)

```xml:activity_main.xml
    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/zero_text_view"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:gravity="center"
            android:text="This is"
            android:textSize="32sp"
            app:layout_constraintBottom_toTopOf="@id/one_include"
            app:layout_constraintTop_toTopOf="parent" />

        <include
            android:id="@+id/one_include"
            layout="@layout/one_layout"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/zero_text_view"/>
    </androidx.constraintlayout.widget.ConstraintLayout>
```

アプリを実行すると次のように表示されます。
このように Include タグを利用すれば Layout を簡単に再利用できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79387/57bd793e-51fa-6eba-a16b-b1d66ccac402.png)

# Databinding するデータを Include に反映させるには

Databinding では layout タグと data タグに利用するデータを
variable タグにて宣言しデータとビューをバインドできるようにします。

```xml:activity_main.xml
<layout xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
        <variable name="viewModel" type="kaleidot725.myapplication.MainViewModel" />
    </data>
      
      ︙
      ︙
</layout>
```

まずはInclude する場合も Databinding する手順はかわらず、
埋め込む側と埋め込まれる側の両方で必要なデータを宣言し利用します。

**埋め込まれる側の Layout ファイル**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79387/318eab4f-5a51-706d-ef56-a3eef0f3ee7b.png)

```xml:one_fragment
<layout>

    <data>
        <variable name="viewModel" type="kaleidot725.myapplication.MainViewModel" />
    </data>

    <FrameLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="@{viewModel.oneLayoutMessage}"
            android:textSize="32sp"
            />
    </FrameLayout>
</layout>
```

**埋め込む側の Layout ファイル**

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79387/29ed782f-a0d0-81ac-57a4-6e1d08e2c07e.png)

```xml:activity_main.xml
<layout xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>
        <variable name="viewModel" type="kaleidot725.myapplication.MainViewModel" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:id="@+id/zero_text_view"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:gravity="center"
            android:text="@{viewModel.activityLayoutMessage}"
            android:textSize="32sp"
            app:layout_constraintBottom_toTopOf="@id/one_include"
            app:layout_constraintTop_toTopOf="parent" />

        <include
            android:id="@+id/one_include"
            layout="@layout/one_layout"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@id/zero_text_view"/>

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>
```

**MainViewModel**

```kotlin:MainViewModel
class MainViewModel : ViewModel() {
    private val _activityLayoutMessage: MutableLiveData<String> = MutableLiveData("This is")
    val activityLayoutMessage: LiveData<String> = _activityLayoutMessage

    private val _oneLayoutMessage: MutableLiveData<String> = MutableLiveData("Good Sample")
    val oneLayoutMessage: LiveData<String> = _oneLayoutMessage
}
```

そして MainAcitvity にて ViewModel を設定する処理を
記述すれば通常は Databinding できるようになります。

**MainViewModelをバインドする処理**

```kotlin:MainActivity.kt
class MainActivity : AppCompatActivity() {

    private val viewModel by viewModels<MainViewModel>()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main).apply {
            viewModel = this@MainActivity.viewModel
            lifecycleOwner = this@MainActivity
        }
    }
}
```

ですが今回は Include を利用しているので、もう１つ記述が必要になります。
なぜなら MainAcitivty にて ViewModel を設定する処理だけでは、
Include した箇所にまで ViewModel を設定してくれないからです。
Include した箇所にも反映させるには、Includeタグに app:Variable名称 設定する必要があります。

```xml
  <include
      android:id="@+id/one_include"
      app:viewModel="@{viewModel}"
          ︙
      />
```

この状態で起動すると、うまく動作します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79387/cdd152ed-cfae-d574-81b5-17569cfe3af5.png)

# 参考文献!
- [Re-using layouts with <include/> | Android Developers](https://developer.android.com/training/improving-layouts/reusing-layouts)