[Android アプリの UI デザイン] Layer List の作りかたのまとめと Tips

2013.04.10

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Layer List について

Layer List とは画像などをレイヤー構成で重ねることができるリソースです。複数の画像をひとつのリソースとして取り扱うことができます。

layer_list01

うまく使うととっても便利ですし、リソースの削減にもなるのでぜひとも使いこなしたいところです。
そんな便利な Layer List の作りかたと Tips をまとめてみました!

Layer List の作りかたの基本

ということで早速 Layer List の作りかたを学んでいきましょう。ご存知のかたは復習がてらにさらりと目を通していただければ幸いです。
お試しとして以下のような2つの画像から構成される Layer List を作ってみたいと思います!角丸の付きの黒いグラデーションの背景に Droid くんが乗っかってるような構成です。

layer_list02

XML で作る

XML で作る場合は layer-list タグを使います。そのタグの中に item タグで要素を構成していきます。上に書いた順に描画されるので、一番上の item タグで定義した画像が一番下に表示されます。なので、まず背景を item タグで定義したあとに Droid くんの item タグを定義します。以下のよう感じです。

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >

    <!-- 角丸付きの黒いグラデーションの背景(Shapeで書いてみた) -->
    <item>
        <shape>
            <corners android:radius="10dp"/>
            <gradient
                android:angle="90"
                android:endColor="#606060"
                android:startColor="#323232" />
        </shape>
    </item>

    <!-- Droidくんの画像 -->
    <item
        android:drawable="@drawable/droid"
        android:top="10dp"
        android:bottom="10dp"
        android:left="10dp"
        android:right="10dp"/>

</layer-list>

上記の Droid くんの画像の item タグ 内で topbottomleftright などの指定を行なっておりますが、これはパディングです。10dp ずつあけているので、黒いグラデーション背景より上下左右に10dpの間隔をあけて Droid くんが描画されるようになります。
あとはこの Drawable を View に設定して完了です!

<ImageView
    android:id="@+id/image_view"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="@drawable/layer_list_sample"
    />

Java で作る

Java ソース上で同様の Layer List を作る場合は以下のように実装します。

// LayerDrawable の素材となる Drawable を取得
Resources r = getResources();
Drawable shape = r.getDrawable(R.drawable.shape_sample);
Drawable droid = r.getDrawable(R.drawable.droid);

// LayerDrawable を生成
Drawable[] layers = { shape, droid };
LayerDrawable layerDrawable = new LayerDrawable(layers);

// padding を設定する
int padding = r.getDimensionPixelSize(R.dimen.padding);
layerDrawable.setLayerInset(1, padding, padding, padding, padding);

// View にセットする
ImageView view = (ImageView) findViewById(R.id.image_view);
view.setImageDrawable(layerDrawable);

Layer List にする Drawable は LayerDrawable というクラスで作ります。コンストラクタ引数に LayerDrawable に入れたい Drawable を配列で渡します。すると配列の順番通り、下から描画されます。
またパディングを指定する場合は setLayerInset() を使います。第一引数にはパディングを設定する対象の Drawable の index を渡します。今回は配列の2番目の Drawable なので index は 1 になってます。

Tips など

Layer List の item を別な Drawable に動的に入れ替える

一度作った Layer List の任意の item を別な Drawable に動的に切り替えることができます。切り替えるときは LayerDrawable#setDrawableByLayerId() メソッドを使います。
参考としてボタンをタップすると ImageView に描画している Layer List の一番上の item が切り替わるサンプルを作ってみたいと思います。まずは Layer List の XML ファイルで動的に変更したい itemandroid:id を付けます。

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >

    <!-- 角丸付きの黒いグラデーションの背景 -->
    <item>
        <shape>
            <corners android:radius="10dp"/>
            <gradient
                android:angle="90"
                android:endColor="#606060"
                android:startColor="#323232" />
        </shape>
    </item>

    <!-- Droidくんの画像 -->
    <item
        android:id="@+id/droid"
        android:bottom="10dp"
        android:drawable="@drawable/droid"
        android:left="10dp"
        android:right="10dp"
        android:top="10dp"/>

</layer-list>

あとは OnClickListener#onClick() メソッド内で LayerDrawable を取得して LayerDrawable#setDrawableByLayerId() を呼びます。第一引数に先ほど android:id で定義した id を、第二引数には新しく差し替える Drawable を指定します。最後に LayerDrawable#invalidateSelf() を呼んで再描画してあげて完了です!

ImageView view = (ImageView) findViewById(R.id.image_view);
LayerDrawable layer = (LayerDrawable) view.getDrawable();

// LayerDrawable の素材となる Drawable を取得
Drawable droid = getResources().getDrawable(R.drawable.droid_blue);
layer.setDrawableByLayerId(R.id.droid, droid);
layer.invalidateSelf();

実行して Change ボタンをタップすると以下のように青色の Droid くんに入れ替わります。

layer_list03

Android 4.0 未満のバージョンだと invalidateSelf() を呼ぶと消える

上記で使った LayerDrawable#invalidateSelf() メソッドですが、Android 4.0 未満のバージョンではこのメソッドを呼ぶと描画されず消えてしまうようです。

layer_list04

そんなときは以下のように入れ替え前の Drawable から Bounds を取得し、入れ替え後の Drawable にセットしてあげます。

ImageView view = (ImageView) findViewById(R.id.image_view);
LayerDrawable layer = (LayerDrawable) view.getDrawable();

// LayerDrawable の素材となる Drawable を取得
Drawable droid = getResources().getDrawable(R.drawable.droid_blue);
// 入れ替え前の Drawable から Bounds を取得してセットする
Rect bounds = layer.findDrawableByLayerId(R.id.droid).getBounds();
droid.setBounds(bounds);
layer.setDrawableByLayerId(R.id.droid, droid);
layer.invalidateSelf();

layer_list05

まとめ

以上 Layer List の作りかたのまとめとちょっとした Tips でした。
うまく使うことができればリソースの削減になると思うのでぜひ使っていきましょう!

参考