Drawableのarrayをxmlファイルに定義して、ビューの属性として読み込ませる

* Drawableのarrayをxmlファイルに定義する
* ビューの属性としてarrayを設定して読み込ませる

の2つの方法はそれぞれググればすぐに見つけられますが、

同時にこれをするのは2時間くらい手こずったのでメモ。

# 内容
ScrollViewを継承する独自のビューScrollDrawableViewを作成し、
drawablesという名前の独自の属性を与え、
このdrawables属性にDrawableのarrayを設定すると、
自動的にarrayの中身をScrollViewの中に展開して、画面スクロールでDrawableの画像ファイルを見られるようにします。

完成するとこうなります。画面スクロールで画像を見ていけるようになってます。
![完成図.png](https://qiita-image-store.s3.amazonaws.com/0/44676/05eaae1b-4b4c-c73b-73f2-ab1a599082c8.png)

# Drawableのarrayのxmlファイル
res/drawableに、今回表示させるa.pngからu.pngまでを置いてあります。
`drawables`という名前のarrayに`<item>@drawable/a</item>`とアイテムを列挙しているだけですが一応書いておきます。

```xml:arrays.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <array name="pictures">
        <item>@drawable/a</item>
        <item>@drawable/b</item>
        <item>@drawable/c</item>
        <item>@drawable/d</item>
        <item>@drawable/e</item>
        <item>@drawable/f</item>
        <item>@drawable/g</item>
        <item>@drawable/h</item>
        <item>@drawable/i</item>
        <item>@drawable/j</item>
        <item>@drawable/k</item>
        <item>@drawable/l</item>
        <item>@drawable/m</item>
        <item>@drawable/n</item>
        <item>@drawable/o</item>
        <item>@drawable/p</item>
        <item>@drawable/q</item>
        <item>@drawable/r</item>
        <item>@drawable/s</item>
        <item>@drawable/t</item>
        <item>@drawable/u</item>
    </array>

</resources>
```

# 独自の属性を定義するxmlファイル

```xml:attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="ScrollDrawableView">
        <attr name="drawables" format="reference" />
    </declare-styleable>

</resources>
```

`declare-styleable`のnameは何でもいいのですが、わかりやすいように、自分で独自に作成するビュークラスのクラス名や、用途を書くといいと思います。
`attr`のformatは文字列ならstring、数値ならinteger、といった具合にそれ専用で用意されている値がいくつかありますが、Drawableにはそれがないので、`reference`にします。
これで独自の属性を定義できました。

# レイアウトのxmlファイル
アプリのパッケージ名はcom.exampleにしてあります。
MainActivityのレイアウトとして使用するactivity_main.xmlです。
com.example.view.ScrollDrawableViewはScrollViewを継承して自分で作成したビューです。


```xml:activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:custom="http://schemas.android.com/apk/res/com.example"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <com.example.view.ScrollDrawableView
        android:id="@+id/picker"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scrollbars="none"
        custom:drawables="@array/pictures" />

</LinearLayout>
```

独自の属性を使用するために、`xmlns:custom="http://schemas.android.com/apk/res/com.example"`で名前空間を設定します。
これで自分で定義した属性をcustomという名前空間で使えるので、`custom:drawables="@array/drawables"`をビューに設定します。
あとは、ScrollDrawableViewクラスで、drawables属性に指定したarrayのDrawableをImageViewにセットして使用するコードを書くだけです。

# 独自ビューで独自属性を解釈する
コンストラクタの引数の`AttributeSet attrs`を使い、設定されている属性のうちから独自に作成した属性を探して、その属性の値として指定されているarrayを取得する流れです。
途中に出てくる`R.styleable.ScrollDrawableView_drawables`は、
R.javaの中へと自動的に作成される、
attr.xmlで定義したdeclare-styleableのnameの`ScrollDrawableView`と、
attrのnameの`drawables`を"_"で連結している名前です。
独自属性を作成したときに勝手に決められるのでちょっとわかりにくいですね。

```java:ScrollDrawableView
package com.example.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import com.example.R;

public class ScrollDrawableView extends ScrollView {
	private final int ELEMENT_WIDTH_HEIGHT = getResources().getDimensionPixelSize(R.dimen.side_length);
	private final LayoutParams ELEMENT_LAYOUT_PARAMS = new LayoutParams(ELEMENT_WIDTH_HEIGHT, ELEMENT_WIDTH_HEIGHT);

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

		// ScrollViewは中に1つしかビューを持てないので、LinearLayoutの中にDrawableのarrayを入れていくことにする
		LinearLayout linearLayout = new LinearLayout(context);
		linearLayout.setOrientation(LinearLayout.VERTICAL);

		// ビューのdrawables属性の値として指定されている、drawableのarrayのリソースIDを取得
		TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ScrollDrawableView);
		int resourceId = typedArray.getResourceId(R.styleable.ScrollDrawableView_drawables, -1);
		typedArray.recycle();

		// arrayの中身のDrawableをImageViewにセットして使用
		TypedArray drawableArray = getResources().obtainTypedArray(resourceId);
		int length = drawableArray.length();
		for (int i = 0; i < length; i++) {
			Drawable drawable = drawableArray.getDrawable(i);
			ImageView imageView = new ImageView(context);
			imageView.setLayoutParams(ELEMENT_LAYOUT_PARAMS);
			imageView.setImageDrawable(drawable);
			linearLayout.addView(imageView);
		}
		drawableArray.recycle();

		addView(linearLayout);
	}
}
```

# アクティビティ
setContentViewでレイアウトのxmlファイルをセットしているだけですが、一応書いておきます。

```java:MainActivity.java
package com.example;

import android.app.Activity;
import android.os.Bundle;

public class MainActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
	}
}
```