今天和大家分享关于“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接口:
01 |
/*** |
02 |
* <span class="referer">@author</span> huangsm |
03 |
* @date 2012-8-29 |
04 |
* <span class="referer">@email</span> [email protected] |
05 |
* @desc 接口 |
06 |
*/ |
07 |
public interface ListItems { |
08 |
09 |
public int getLayout(); |
10 |
|
11 |
public boolean isClickable(); |
12 |
|
13 |
public View getView(Context context, View convertView, LayoutInflater inflater); |
14 |
|
15 |
} |
其中LabelItem和ContentItem分别是显示的“类别”和“内容”,他们分别实现ListItems接口。LabelItem实现:
01 |
/*** |
02 |
* <span class="referer">@author</span> huangsm |
03 |
* @date 2012-8-29 |
04 |
* <span class="referer">@email</span> [email protected] |
05 |
* @desc 标签 |
06 |
*/ |
07 |
public class LabelItem implements ListItems { |
08 |
09 |
private String mLabel; |
10 |
public LabelItem(String label){ |
11 |
mLabel = label; |
12 |
} |
13 |
|
14 |
@Override |
15 |
public int getLayout() { |
16 |
return R.layout.label_layout; |
17 |
} |
18 |
19 |
@Override |
20 |
public boolean isClickable() { |
21 |
return false ; |
22 |
} |
23 |
24 |
@Override |
25 |
public View getView(Context context, View convertView, LayoutInflater inflater) { |
26 |
convertView = inflater.inflate(getLayout(), null ); |
27 |
TextView title = (TextView) convertView; |
28 |
title.setText(mLabel); |
29 |
return convertView; |
30 |
} |
31 |
32 |
} |
ContentItem的实现:
01 |
/*** |
02 |
* <span class="referer">@author</span> huangsm |
03 |
* @date 2012-8-29 |
04 |
* <span class="referer">@email</span> [email protected] |
05 |
* @desc 内容 |
06 |
*/ |
07 |
public class ContentItem implements ListItems { |
08 |
09 |
private Item mItem; |
10 |
public ContentItem(Item item){ |
11 |
mItem = item; |
12 |
} |
13 |
|
14 |
@Override |
15 |
public int getLayout() { |
16 |
return R.layout.content_layout; |
17 |
} |
18 |
19 |
@Override |
20 |
public boolean isClickable() { |
21 |
return true ; |
22 |
} |
23 |
24 |
@Override |
25 |
public View getView(Context context, View convertView, LayoutInflater inflater) { |
26 |
convertView = inflater.inflate(getLayout(), null ); |
27 |
ImageView iv = (ImageView) convertView.findViewById(R.id.content_image); |
28 |
iv.setImageResource(mItem.getResid()); |
29 |
TextView tv = (TextView) convertView.findViewById(R.id.content_text); |
30 |
tv.setText(mItem.getTitle()); |
31 |
return convertView; |
32 |
} |
33 |
} |
在activity中实现就相对来说比较麻烦一些。定义一个以ListItems为泛型的list集合mListItems,作为填充adapter的数据源,然后在adapter里面处理就很简单:
01 |
class PartAdapter extends BaseAdapter { |
02 |
03 |
@Override |
04 |
public int getCount() { |
05 |
return mListItems.size(); |
06 |
} |
07 |
08 |
@Override |
09 |
public Object getItem( int position) { |
10 |
return mListItems.get(position); |
11 |
} |
12 |
13 |
@Override |
14 |
public long getItemId( int position) { |
15 |
return position; |
16 |
} |
17 |
|
18 |
@Override |
19 |
public boolean isEnabled( int position) { |
20 |
return mListItems.get(position).isClickable(); |
21 |
} |
22 |
23 |
@Override |
24 |
public View getView( int position, View convertView, ViewGroup parent) { |
25 |
return mListItems.get(position).getView(mContext, convertView, mInflater); |
26 |
} |
27 |
} |
接下来是初始化数据,需要注意的是LabelItem的初始化,不过这个动作可以在你打包数据的时候处理好,这样在activity里面就不会那么麻烦了