Spinnerにenumを使いたいときのアプローチ

## やりたいこと
- Spinnerの選択項目にenumを使いたい
- 表示文字列はstrings.xmlのものを使いたい
- 内部的なデータとしてはStringやintを使いたい

## 準備

### 便利クラスと、それ用のinterfaceを定義する

#### ICodeLabel.java
enumに実装させるメソッドのinterfaceです。

```java
public interface ICodeLabel {
    /** 内部的なデータとして扱うための文字列を返すメソッドです。 */
    String getCode();

    /** 表示文字列を返すためのメソッドです。 */
    String getLabel(Resources res);
}
```

#### CodeLabelAdapter.java
前述のICodeLabelを実装したクラスを表示するためのAdapterです。

```java
public class CodeLabelAdapter extends ArrayAdapter<ICodeLabel> {
    @LayoutRes
    private int mResource;
    @LayoutRes
    private int mDropDownResource;

    public static CodeLabelAdapter newInstance(Context context, ICodeLabel[] objects, boolean withNullValue) {
        if (withNullValue) {
            List<ICodeLabel> values = new ArrayList<>();
            values.add(null);
            values.addAll(Arrays.asList(objects));
            return new CodeLabelAdapter(context, android.R.layout.simple_list_item_1, android.R.layout.simple_spinner_dropdown_item, values);
        } else {
            return new CodeLabelAdapter(context, android.R.layout.simple_list_item_1, android.R.layout.simple_spinner_dropdown_item, objects);
        }
    }

    public static CodeLabelAdapter newInstance(Context context, List<ICodeLabel> objects, boolean withNullValue) {
        if (withNullValue) {
            List<ICodeLabel> values = new ArrayList<>();
            values.add(null);
            values.addAll(objects);
            return new CodeLabelAdapter(context, android.R.layout.simple_list_item_1, android.R.layout.simple_spinner_dropdown_item, values);
        } else {
            return new CodeLabelAdapter(context, android.R.layout.simple_list_item_1, android.R.layout.simple_spinner_dropdown_item, objects);
        }
    }

    public CodeLabelAdapter(Context context, @LayoutRes int resource, @LayoutRes int dropDownResource, ICodeLabel[] objects) {
        super(context, resource, objects);
        mResource = resource;
        mDropDownResource = dropDownResource;
    }

    public CodeLabelAdapter(Context context, @LayoutRes int resource, @LayoutRes int dropDownResource, List<ICodeLabel> objects) {
        super(context, resource, objects);
        mResource = resource;
        mDropDownResource = dropDownResource;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = LayoutInflater.from(getContext()).inflate(mResource, null);
        }
        TextView view = (TextView) convertView.findViewById(android.R.id.text1);
        ICodeLabel item = getItem(position);
        if (item != null) {
            view.setText(item.getLabel(getContext().getResources()));
        } else {
            view.setText("");
        }
        return view;
    }

    @Override
    public View getDropDownView(int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            convertView = LayoutInflater.from(getContext()).inflate(mDropDownResource, null);
        }
        TextView view = (TextView) convertView.findViewById(android.R.id.text1);
        ICodeLabel item = getItem(position);
        if (item != null) {
            view.setText(item.getLabel(getContext().getResources()));
        } else {
            view.setText("");
        }
        return view;
    }
}

```

## enumの実装の例

### strings.xmlを準備する
基本的に言語別に普通に作成したら良いです。

#### values/strings.xml

```xml
<resources>
    <string name="ordinal_label_first">First</string>
    <string name="ordinal_label_second">Second</string>
    <string name="ordinal_label_third">Third</string>
    <string name="ordinal_label_fourth">Fourth</string>
</resources>
```

#### values-ja/strings.xml

```xml
<resources>
    <string name="ordinal_label_first">ひとつめ</string>
    <string name="ordinal_label_second">ふたつめ</string>
    <string name="ordinal_label_third">みっつめ</string>
    <string name="ordinal_label_fourth">よっつめ</string>
</resources>
```

#### OrdinalLabel.java

```java
public enum OrdinalLabel implements ICodeLabel {
    FIRST("first", R.string.ordinal_label_first),
    SECOND("second", R.string.ordinal_label_second),
    THIRD("third", R.string.ordinal_label_third),
    FOURTH("fourth", R.string.ordinal_label_fourth),
    ;

    final String code;
    @StringRes
    final int resId;

    OrdinalLabel(String code, @StringRes int resId) {
        this.code = code;
        this.resId = resId;
    }

    @Override
    public String getCode() {
        return code;
    }

    @Override
    public String getLabel(Resources res) {
        return res.getString(resId);
    }
}
```

## SpinnerへのAdapterの設定の例

```java
// find views
mSpinner = (Spinner) findViewById(R.id.spinner);

// set adapter
mSpinner.setAdapter(CodeLabelAdapter.newInstance(this, OrdinalLabel.values(), true));
```


## サンプルアプリ
https://github.com/cattaka/AndroidSnippets