ListViewまわりのあれこれをメモ2です。

ExpandableListAdapterをカスタムする際のメモ。
BaseExpandableListAdapterの使い方とか見るとごっちゃりしとるので
今回は使いまわししたいBindableAdapterの作り方を元に同じように使えるBaseExpandableListAdapterを作ってみる。


それでは。。。
BaseExpandableListAdapterですが、ListAdapterのgetViewに相当するものが以下です。

//親のView
public View getGroupView(int groupPosition, boolean isExpanded, View convertView,ViewGroup parent);

//子供のView
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent);

なのでここをBindableAdapterのようにしてやれば終わり。
あとはget関係などは継承してもついてないのでgetGroupCountとか自分で設置する必要はあります。

ざざっとかいてしまうと以下です。
*子データをよくMapにしているサンプルがありますが個人的にリストのほうが管理しやすいのでListにしてます。

public abstract class BindableExpandableAdapter<G,C> extends BaseExpandableListAdapter {

    private LayoutInflater mInflater;
    private List<G> mGroupData;
    private List<List<C>> mChildData;
    public BindableExpandableAdapter(Context context, List<G> laptops,
     List<List<C>> laptopCollections) {
        //this.context = context;
        this.mChildData = laptopCollections;
        this.mGroupData = laptops;

        init(context);
    }
    
    private void init(Context context) {
        mInflater = LayoutInflater.from(context);
    }

    public C getChild(int groupPosition, int childPosition) {
        return mChildData.get(groupPosition).get(childPosition);
    }


    public int getChildrenCount(int groupPosition) {
        return mChildData.get(groupPosition).size();
    }

    public long getChildId(int groupPosition, int childPosition) {
        return childPosition;
    }

    public boolean getLastChild(int groupPosition, int childPosition) {
        return mChildData.get(groupPosition).size()-1==childPosition?true:false;
    }
    

    public G getGroup(int groupPosition) {
        return mGroupData.get(groupPosition);
    }

    public int getGroupCount() {
        return mGroupData.size();
    }

    public long getGroupId(int groupPosition) {
        return groupPosition;
    }

    
    public boolean isChildSelectable(int groupPosition, int childPosition) {
        return true;
    }

    public boolean hasStableIds() {
        return true;
    }

    public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
            ViewGroup parent) {
        View v;
        if (convertView == null) {
            v = newGroupView(mInflater, groupPosition, parent,isExpanded);
            if (v == null) {
                throw new IllegalStateException("newGroupView result must not be null.");
            }
        } else {
            v = convertView;
        }
        bindGroupView( mGroupData.get(groupPosition), groupPosition,v,isExpanded);
        return v;
    }

    public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
            View convertView, ViewGroup parent) {
        View v;
        if (convertView == null) {
            v = newChildView(mInflater,groupPosition,childPosition,parent,isLastChild);
            if (v == null) {
                throw new IllegalStateException("newChildView result must not be null.");
            }
        } else {
            v = convertView;
        }
        bindChildView( mChildData.get(groupPosition).get(childPosition),groupPosition,childPosition,v,isLastChild);
        return v;
    }


    public abstract View newGroupView(LayoutInflater inflater, int groupPosition, ViewGroup container,boolean isExpanded);
    public abstract View newChildView(LayoutInflater inflater, int groupPosition, int childPosition, ViewGroup container, boolean isLastChild);
    public abstract void bindGroupView( G item,  int groupPosition,View view,boolean isExpanded);
    public abstract void bindChildView(C item,int groupPosition, int childPosition,View view, boolean isLastChild);
}

あとはこのClassを継承して好きにカスタマイズしたAdapterを作ってExpandableListView.setAdapter(adapter)してあげればOK。
*Obj, ChildObjはカスタムオブジェクトです。

public class MyExpandableAdapter extends BindableExpandableAdapter<Obj, ChildObj> {

public MyExpandableAdapter(Context context, List<Obj> laptops,
List<List<ChildObj>> laptopCollections) {
super(context, laptops, laptopCollections);
}

private static class ViewGroupHolder {
private TextView label1,label2;
private ImageView indicator;
ViewGroupHolder(View view) {
label1= (TextView) view.findViewById(android.R.id.text1);
label2= (TextView) view.findViewById(android.R.id.text2);
indicator= (ImageView) view.findViewById(R.id.indicator);
}
}
@Override
public View newGroupView(LayoutInflater inflater, int groupPosition,
ViewGroup container, boolean isExpanded) {
View view = inflater.inflate(R.layout.group_row,
container, false);
ViewGroupHolder holder = new ViewGroupHolder(view);
view.setTag(holder);
return view;
}

@Override
public void bindGroupView(Obj item, int groupPosition, View view,boolean isExpanded) {
ViewGroupHolder holder = (ViewGroupHolder) view.getTag();

holder.label1.setText(item.name1);
holder.label2.setText(item.name2);

holder.indicator.setVisibility(View.GONE);
if(getChildrenCount(groupPosition)==0){
holder.indicator.setVisibility(View.GONE);
}else{
holder.indicator.setImageResource( isExpanded ? R.drawable.expander_open_holo_light : R.drawable.expander_close_holo_light );
holder.indicator.setVisibility(View.VISIBLE);
}
}
private static class ViewChildHolder {
private CheckedTextView label;
ViewChildHolder(View view) {
label = (CheckedTextView) view.findViewById(android.R.id.text1);
}
}


@Override
public View newChildView(LayoutInflater inflater, int groupPosition,
int childPosition, ViewGroup container, boolean isLastChild) {
View view = inflater.inflate(R.layout.child_row,
container, false);
ViewChildHolder holder = new ViewChildHolder(view);
view.setTag(holder);
return view;
}


@Override
public void bindChildView(ChildObj item, int groupPosition,
int childPosition, View view, boolean isLastChild) {
ViewChildHolder holder = (ViewChildHolder) view.getTag();
holder.label.setText(item.name);
holder.label.setChecked(item.check);
}
}


OnChildClickListenerとかで返ってきたViewなどを使ってbindGroupView()やbindChildView()を呼べばnotifyDataSetChangedなど使わず、直接Viewを更新できますので便利です。
*BindableAdapterでもできます。


[メモ]ListViewから個別にViewを取り出すやり方。と組み合わせればListener以外からでも対象のViewが取れるのでいつでも直に更新できる感じになります。

特に説明せずコードだけ置いてすいません。
こんなところで。

今回の話はサンプルファイルでいうとMyArrayAdapter(継承元 BindableAdapter)MyExpandableAdapter(継承元 BindableExpandableAdapter)になります。

ListViewまわりのあれこれをメモ1,2のサンプルはこちら