ASとか

開発系の記事が多めです。タイトルのASはActionScriptの略です。

セクション毎の区切り用ビュー付きListView

実装するにあたり

  • iOSのようにデフォルトで区切り用ビューを提供していない
    • 普通のビューを作る感覚で区切り用ビューも作らなければいけない
  • ルール決めした配列を渡すだけで区切り用ビュー表示までは自動でやってもらいたい

実装

listview_sep.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="wrap_content"
    android:paddingLeft="10px"
    android:background="#AAA"
    android:layout_width="fill_parent"
    android:orientation="vertical">
    <TextView
        android:layout_height="wrap_content"
        android:textColor="#FFFFFF"
        android:text="タイトル"
        android:id="@+id/section_title"
        android:layout_width="fill_parent">
    </TextView>
</LinearLayout>
SeparateArrayAdapter.java
public class SeparateArrayAdapter extends ArrayAdapter<Object> {

    /**
     * String型かList型かで区切りか否かを判定するため原型を保持しておく
     */
    private List<Object> objects = null;

    private LayoutInflater inflater = null;

    /**
      * 第三引数には
      *  ・セクションタイトル(String)
      *  ・セクション表示用アイテム(List<Object>)
      * がセクション毎に並んでいるList<Object>を渡すこと
      * @param context
      * @param textViewResourceId
      * @param objects
      */
    @SuppressWarnings("unchecked")
    public SeparateArrayAdapter(Context context, int textViewResourceId,
            List<Object> objects) {
        super(context, textViewResourceId, new ArrayList<Object>());
        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        this.objects = objects;
        // getCount(), getItem()を上書かなくてもいいようここで整形
        for (Object obj : objects) {
            if (obj instanceof String) {
                add(obj);
            }
            else {
                for (Object item : (List<Object>) obj) {
                    add(item);
                }
            }
        }
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        Object obj = getItem(position);
        // 区切りでない
        if (isEnabled(position)) {
            convertView = getCustomView(obj, convertView);
        }
        // 区切り
        else {
            convertView = inflater.inflate(R.layout.listview_sep, null);
            ((TextView) convertView.findViewById(R.id.section_title)).setText((String) obj);
        }
        return convertView;
    }

    /**
      * 区切り用ビュー以外のビュー作成メソッド
      * @param obj
      * @param convertView
      * @return objを元にカスタムしたビュー
      */
    protected View getCustomView(Object obj, View convertView) {
        if (null == convertView || convertView.getId() != android.R.layout.simple_list_item_1)
            convertView = inflater.inflate(android.R.layout.simple_list_item_1, null);
        ((TextView) convertView.findViewById(android.R.id.text1)).setText((String) obj);
        return convertView;
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean isEnabled(int position) {
        int currentNumber = 0;
        for (Object obj : objects) {
            if (obj instanceof String) {
                if (position == currentNumber) {
                    return false;
                }
            currentNumber++;
            }
            else {
                for (int i = 0; i < ((List<Object>) obj).size(); i++) {
                    if (position == currentNumber) {
                        return true;
                    }
                    currentNumber++;
                }
            }
        }
        return true;
    }
}

解説

  • コンストラクタ
    • 第三引数はそのまま保持し、自身にはバラしたものをaddしておく
  • getCustomView(Object obj, View convertView)
    • 区切り用ビューはgetView(int position, View convertView, ViewGroup parent)の方で作成するのでここだけ実装すればOK
  • isEnabled(int position)
    • ビューの活性or非活性を選択できるので、区切り用フィールドの時はfalseを返す

今度は

データ追加した時のパターンとか全く考慮してないですね。また触る時間があれば大幅に書き直したいです。