ListView分類顯示
今天和大家分享關于“listview的分類顯示”。現在有比較多的應用都有這個效果,比如在android的ICS風格的“設置”選項里面就有這個效果,先看看效果:

實現這個效果比較簡單,在填充listview的adapter的時候,我們都會通過繼承BaseAdapter來寫我們自己的adapter,listview里面的item是通過getView(int position, View convertView, ViewGroup parent) 實現。其實這邊有實現預加載,你只要在getview方法里面打印出log信息就會發現,listview剛開始顯示的時候getview不會返回所有的item,只是返回了前面幾個,當你往下拖拽的時候getview方法會加載剩下的item。這樣做的好處大家都知道,如果不這樣做估計早就出現了內存泄漏了。
好吧,我們回到主題,實現分類顯示只需要你把你顯示的數據打包好。Listview里面的item都是通過getView來生成,所以可以這樣,如果在getview里面生成item的時候,你返回兩次convertView不就可以了嗎?也就是說平時我們都是通過convertView來返回item,但是現在多了一個操作就是你根據自身打包的數據,如果當前返回的item是和之前顯示的item不屬于同一類就返回兩次convertView。這樣理解這個就好實現多了吧。注意的是像上面圖上“Label”、“類別1”、“類別2”是不可點擊的,只要實現BaseAdapter里面的isEnabled(int position)的方法就可以。
下面介紹的實現方式是運用了工廠模式實現,下面是草圖

新建了一個ListItems接口:
/*** * @author huangsm * @date 2012-8-29 * @email huangsanm@gmail.com * @desc 接口 */ public interface ListItems { public int getLayout(); public boolean isClickable(); public View getView(Context context, View convertView, LayoutInflater inflater); }其中LabelItem和ContentItem分別是顯示的“類別”和“內容”,他們分別實現ListItems接口。LabelItem實現:
/*** * @author huangsm * @date 2012-8-29 * @email huangsanm@gmail.com * @desc 標簽 */ public class LabelItem implements ListItems { private String mLabel; public LabelItem(String label){ mLabel = label; } @Override public int getLayout() { return R.layout.label_layout; } @Override public boolean isClickable() { return false; } @Override public View getView(Context context, View convertView, LayoutInflater inflater) { convertView = inflater.inflate(getLayout(), null); TextView title = (TextView) convertView; title.setText(mLabel); return convertView; } }ContentItem的實現:
/*** * @author huangsm * @date 2012-8-29 * @email huangsanm@gmail.com * @desc 內容 */ public class ContentItem implements ListItems { private Item mItem; public ContentItem(Item item){ mItem = item; } @Override public int getLayout() { return R.layout.content_layout; } @Override public boolean isClickable() { return true; } @Override public View getView(Context context, View convertView, LayoutInflater inflater) { convertView = inflater.inflate(getLayout(), null); ImageView iv = (ImageView) convertView.findViewById(R.id.content_image); iv.setImageResource(mItem.getResid()); TextView tv = (TextView) convertView.findViewById(R.id.content_text); tv.setText(mItem.getTitle()); return convertView; } }
在activity中實現就相對來說比較麻煩一些。定義一個以ListItems為泛型的list集合mListItems,作為填充adapter的數據源,然后在adapter里面處理就很簡單:
class PartAdapter extends BaseAdapter {
@Override
public int getCount() {
return mListItems.size();
}
@Override
public Object getItem(int position) {
return mListItems.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public boolean isEnabled(int position) {
return mListItems.get(position).isClickable();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return mListItems.get(position).getView(mContext, convertView, mInflater);
}
}
接下來是初始化數據,需要注意的是LabelItem的初始化,不過這個動作可以在你打包數據的時候處理好,這樣在activity里面就不會那么麻煩了 @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.part_listview);
mListView = (ListView) findViewById(R.id.part_list);
mContext = this;
mInflater = LayoutInflater.from(mContext);
mListItems = new ArrayList
();
//初始化數據
LabelItem label1 = new LabelItem("Label");
mListItems.add(label1);
Item item1 = new Item();
item1.setResid(R.drawable.ic_launcher);
item1.setTitle(getString(R.string.app_name));
ContentItem content1 = new ContentItem(item1);
mListItems.add(content1);
for (int i = 0; i < 3; i++) {
LabelItem label = new LabelItem("類別" + (i + 1));
mListItems.add(label);
for (int j = 0; j < 3; j++) {
Item item = new Item();
item.setResid(R.drawable.ic_launcher_biz);
item.setTitle("Content" + (i + 1));
ContentItem content = new ContentItem(item);
mListItems.add(content);
}
}
//設置adapter
PartAdapter adapter = new PartAdapter();
mListView.setAdapter(adapter);
}