2018/12/11 追記: DataBindingの例を追加しました。
2019/09/18 追記: SpeakerDeckの資料を追加しました
Androidでは、レイアウトを定義するxmlファイルに、他のファイルで定義したレイアウトを読み込ませることができます。「そんなことできて当たり前じゃないか」と言われるようなマイナーな機能ですが、備忘録として。
(こんな方々にヒントになるかもしれません)
- 複数の画面に共通するビューがあるけど、画面ごとにちょっと違う部分もある
- 内容同じなのに、画面ごとにレイアウトを作っていた(IDが重複しちゃいけないと思っていて、など)
includeするだけです
結論から述べると、<include layout="@layout/[layout]" android:id="@+id/[id]"
するだけです!
ConstraintLayoutで<include>
する例をLTで発表したので、スライド資料のリンクを載せておきます。
具体例
<?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 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の例における指定の仕方は、下のようなイメージで可能です。
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 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 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>
以上です。
レイアウトを使いまわして、効率アップ!