レイアウトを使いまわす - 他に定義したレイアウトを読み込ませる方法

**2018/12/11 追記**: DataBindingの例を追加しました。
**2019/09/18 追記**: SpeakerDeckの資料を追加しました

---

Androidでは、レイアウトを定義するxmlファイルに、**他のファイルで定義したレイアウトを読み込ませる**ことができます。「そんなことできて当たり前じゃないか」と言われるようなマイナーな機能ですが、備忘録として。

（こんな方々にヒントになるかもしれません）

- 複数の画面に共通するビューがあるけど、画面ごとにちょっと違う部分もある
- 内容同じなのに、画面ごとにレイアウトを作っていた（IDが重複しちゃいけないと思っていて、など）

## includeするだけです

結論から述べると、`<include layout="@layout/[layout]" android:id="@+id/[id]"`するだけです！
ConstraintLayoutで`<include>`する例をLTで発表したので、スライド資料のリンクを載せておきます。

https://speakerdeck.com/sussan0416/reiautowoshi-ihui-su-constraintlayoutbian

### 具体例

```xml:Example1：他で定義したレイアウトを読み込む例
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@android:color/white">

    <!-- included_layout.xml を読み込む -->
    <include layout="@layout/included_layout" android:id="@+id/include_views_1"/>

    <!-- さらに追加したければ、またincludeすれば良い -->
    <include layout="@layout/included_layout" android:id="@+id/include_views_2"/>

    <!-- 独自の実装があれば追加する。includeの前でも後ろでもOK -->

</ScrollView>
```

なんということでしょう。このように、**include**するだけで、簡単に読み込むことができました。
include時には、idも指定しておきます。後から**findViewById**をする際にIDがコンフリクトしないようにするためです。

### 読み込ませるレイアウトの定義は……

いつも通りの定義で大丈夫です。
念のため、例を載せて起きますが、なんの変哲も、種も仕掛けもありません。
別にLinearLayoutである必要もありません。

```xml:Example2：流しこむレイアウトの定義の例
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="wrap_content">

    <!-- いつもどおりの定義です -->
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/textview"/>

</LinearLayout>
```

## findViewByIdの指定方法

いつもの指定に、1回分多く、findViewByIdを行います。
上のExample1の例における指定の仕方は、下のようなイメージで可能です。

```java:Example3：findViewByIdの指定方法の例
TextView tv = (TextView) findViewById(R.id.included_views).findViewById(R.id.textview);
```

### IDが重複していなければ、findViewByIdは1回で済ませられる

レイアウトを複数includeしても、**IDが重複していなければ**、findViewByIdは1回呼ぶだけでviewを取得することができます。一方で、同じレイアウトを繰り返しincludeしたり、同じIDを使用している複数のレイアウトをincludeしたりしている場合は、findViewByIdは2回呼ぶ必要があります。

将来的なメンテナンスを考えると、2回で指定しておくほうがメンテナンスしやすいでしょう。

## DataBindingを使用する場合

一方、DataBindingを使用している場合は、どのようになるでしょうか。ざっと雰囲気を見てみます。
異なる点で言えば、データの渡し方が `app:名前`になっている点でしょうか。
あまり、大きく変わるわけではなさそうです。

### includeする方

```xml:Example3：他で定義したレイアウトを読み込む例（DataBinding）
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <import type="com.example.myapp.viewmodel.ViewModel" />
        <variable
            name="viewModel"
            type="com.example.myapp.viewmodel.ViewModel" />
    </data>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <include
            layout="@layout/layout_to_include"
            app:textColor="@{viewModel.textColor}"
            app:textString="@{viewModel.textString}" />

    </RelativeLayout>
</layout>
```

### 読み込ませるレイアウトの例

DataBindingになっても、さほど変わることはありません。こちらは、普通にDataBindingを使うときと同じ。
今までどおりの実装をするだけです！

```xml:Example4：流しこむレイアウトの定義の例（DataBinding）
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data>
        <variable
            name="textString"
            type="String" />
        <variable
            name="textColor"
            type="Integer" />
    </data>

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <TextView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@{textString}"
            android:textColor="@{textColor}" />
    </RelativeLayout>
</layout>
```

以上です。
レイアウトを使いまわして、効率アップ！

---
参考サイト：
[Anadreline: 同じ構成のレイアウトを別ファイルにしてincludeで使う](http://anadreline.blogspot.jp/2013/08/include.html)