很多情况下, 我们想要ListView上面展示的东西是可以分组的,比如联系人列表,国家列表啊,这样看起来数据的展现比较有层次感,而且也有助于我们快速定位到某一个具体的条目上,具体效果请看下图:

这是前面TodoList小demo的MainActivity,主要是来展现用户添加的任务的,在原来的基础上添加了分组的效果。

接下来我们具体来讲一下这个效果是怎么实现的。

这是利用开源库StickyListHeaders(传送门:https://github.com/emilsjolander/StickyListHeaders)来实现的,这个实现的效果是基于ListView的,而其实也有关于GridView而实现的分组的效果,大家可以参考一下xiaanming的博客(他的文章名字都很长。。。):

Android 使用开源库StickyGridHeaders来实现带sections和headers的GridView显示本地图片效果

0)关于如何导进开源库,大家请参考:如何导进开源库StickyListHeaders

1)然后,我们要想清楚一件事情,即分组的ListView,是包含两部分:Header 和 Item,所以相对应的我们也要为其定义两个Layout,如下:

1.1)task_header.xml

**[html]** [view plain](http://blog.csdn.net/linmiansheng/article/details/20747775#)[copy](http://blog.csdn.net/linmiansheng/article/details/20747775#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/224769)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/224769/fork)
  <div>
    <embed id="ZeroClipboardMovie_1" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="18" height="18" align="middle" name="ZeroClipboardMovie_1">
    </embed>
  </div>
</div>
- <span class="tag"><?</span><span class="tag-name">xml</span> <span class="attribute">version</span>=<span class="attribute-value">&#8220;1.0&#8221;</span> <span class="attribute">encoding</span>=<span class="attribute-value">&#8220;utf-8&#8221;</span><span class="tag">?></span>

- <span class="tag"><</span><span class="tag-name">RelativeLayout</span> <span class="attribute">xmlns:android</span>=<span class="attribute-value">&#8220;http://schemas.android.com/apk/res/android&#8221;</span>

- <span class="attribute">android:layout_width</span>=<span class="attribute-value">&#8220;match_parent&#8221;</span>

- <span class="attribute">android:layout_height</span>=<span class="attribute-value">&#8220;match_parent&#8221;</span>

- <span class="attribute">android:background</span>=<span class="attribute-value">&#8220;@drawable/header_selector&#8221;</span> <span class="tag">></span>

- 
- <span class="tag"><</span><span class="tag-name">TextView</span>

- <span class="attribute">android:id</span>=<span class="attribute-value">&#8220;@+id/tvHeader&#8221;</span>

- <span class="attribute">android:layout_width</span>=<span class="attribute-value">&#8220;wrap_content&#8221;</span>

- <span class="attribute">android:layout_height</span>=<span class="attribute-value">&#8220;match_parent&#8221;</span>

- <span class="attribute">android:layout_gravity</span>=<span class="attribute-value">&#8220;start|left&#8221;</span>

- <span class="attribute">android:padding</span>=<span class="attribute-value">&#8220;5dp&#8221;</span>

- <span class="attribute">android:textColor</span>=<span class="attribute-value">&#8220;@android:color/white&#8221;</span>

- <span class="attribute">android:textSize</span>=<span class="attribute-value">&#8220;17sp&#8221;</span>

- <span class="attribute">android:textStyle</span>=<span class="attribute-value">&#8220;bold&#8221;</span> <span class="tag">/></span>

- 
- <span class="tag"></</span><span class="tag-name">RelativeLayout</span><span class="tag">></span>

因为我们在Header上面只是展现一个日期,所以我们只需要一个TextView即可。

1.2)task_item.xml

**[html]** [view plain](http://blog.csdn.net/linmiansheng/article/details/20747775#)[copy](http://blog.csdn.net/linmiansheng/article/details/20747775#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/224769)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/224769/fork)
  <div>
    <embed id="ZeroClipboardMovie_2" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="18" height="18" align="middle" name="ZeroClipboardMovie_2">
    </embed>
  </div>
</div>
- <span class="tag"><?</span><span class="tag-name">xml</span> <span class="attribute">version</span>=<span class="attribute-value">&#8220;1.0&#8221;</span> <span class="attribute">encoding</span>=<span class="attribute-value">&#8220;utf-8&#8221;</span><span class="tag">?></span>

- <span class="tag"><</span><span class="tag-name">RelativeLayout</span> <span class="attribute">xmlns:android</span>=<span class="attribute-value">&#8220;http://schemas.android.com/apk/res/android&#8221;</span>

- <span class="attribute">android:layout_width</span>=<span class="attribute-value">&#8220;match_parent&#8221;</span>

- <span class="attribute">android:layout_height</span>=<span class="attribute-value">&#8220;32dp&#8221;</span>

- <span class="attribute">android:descendantFocusability</span>=<span class="attribute-value">&#8220;blocksDescendants&#8221;</span>

- <span class="attribute">android:padding</span>=<span class="attribute-value">&#8220;5dip&#8221;</span><span class="tag">></span>

- 
- <span class="tag"><</span><span class="tag-name">ImageView</span>

- <span class="attribute">android:padding</span>=<span class="attribute-value">&#8220;5dp&#8221;</span>

- <span class="attribute">android:layout_centerVertical</span>=<span class="attribute-value">&#8220;true&#8221;</span>

- <span class="attribute">android:id</span>=<span class="attribute-value">&#8220;@+id/ivComplete&#8221;</span>

- <span class="attribute">android:layout_width</span>=<span class="attribute-value">&#8220;wrap_content&#8221;</span>

- <span class="attribute">android:layout_height</span>=<span class="attribute-value">&#8220;match_parent&#8221;</span>

- <span class="attribute">android:layout_alignParentLeft</span>=<span class="attribute-value">&#8220;true&#8221;</span>

- <span class="attribute">android:layout_alignParentTop</span>=<span class="attribute-value">&#8220;true&#8221;</span>

- <span class="attribute">android:contentDescription</span>=<span class="attribute-value">&#8220;@string/imageview_contentdesc&#8221;</span>

- <span class="attribute">android:src</span>=<span class="attribute-value">&#8220;@drawable/handdraw_tick&#8221;</span>

- <span class="attribute">android:visibility</span>=<span class="attribute-value">&#8220;gone&#8221;</span> <span class="tag">/></span>

- 
- <span class="tag"><</span><span class="tag-name">TextView</span>

- <span class="attribute">android:id</span>=<span class="attribute-value">&#8220;@+id/tvTitle&#8221;</span>

- <span class="attribute">android:layout_width</span>=<span class="attribute-value">&#8220;wrap_content&#8221;</span>

- <span class="attribute">android:layout_height</span>=<span class="attribute-value">&#8220;match_parent&#8221;</span>

- <span class="attribute">android:layout_toRightOf</span>=<span class="attribute-value">&#8220;@+id/ivComplete&#8221;</span>

- <span class="attribute">android:gravity</span>=<span class="attribute-value">&#8220;left|center_vertical&#8221;</span>

- <span class="attribute">android:padding</span>=<span class="attribute-value">&#8220;5dp&#8221;</span>

- <span class="attribute">android:textSize</span>=<span class="attribute-value">&#8220;20sp&#8221;</span> <span class="tag">/></span>

- <span class="tag"></</span><span class="tag-name">RelativeLayout</span><span class="tag">></span>

在这里面,我们定义了每一个item要展现的布局,跟平常我们经常用的layout其实是一样的,大家接下来自定义的Adapter也就理解了。

2)第二步,跟平常绑定ListView一样,我们也需要自定义一个Adapter,称之为StickyListTaskAdapter。

我们来看一下 StickListTaskAdapter 完整的代码,如下:

**[java]** [view plain](http://blog.csdn.net/linmiansheng/article/details/20747775#)[copy](http://blog.csdn.net/linmiansheng/article/details/20747775#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/224769)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/224769/fork)
  <div>
    <embed id="ZeroClipboardMovie_3" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="18" height="18" align="middle" name="ZeroClipboardMovie_3">
    </embed>
  </div>
</div>
- <span class="keyword">public</span> <span class="keyword">class</span> StickListTaskAdapter <span class="keyword">extends</span> BaseAdapter

- <span class="keyword">implements</span> SectionIndexer, StickyListHeadersAdapter{

- 
- <span class="keyword">private</span> LayoutInflater layoutInflater;

- <span class="keyword">private</span> List<TodoTask> tasks;

- <span class="keyword">private</span> <span class="keyword">int</span>[] sectionIndices;

- <span class="keyword">private</span> String[] sectionHeaders;

- 
- <span class="keyword">public</span> StickListTaskAdapter(Context context, List<TodoTask> tasks) {

- layoutInflater = LayoutInflater.from(context);

- 
- <span class="keyword">this</span>.tasks = tasks;

- sectionIndices = getSectionIndices();

- sectionHeaders = getSectionHeaders();

- }

- 
- <span class="keyword">public</span> <span class="keyword">void</span> refresh(List<TodoTask> tasks){

- <span class="keyword">this</span>.tasks = tasks;

- sectionIndices = getSectionIndices();

- sectionHeaders = getSectionHeaders();

- notifyDataSetChanged();

- }

- 
- <span class="keyword">private</span> <span class="keyword">int</span>[] getSectionIndices() {

- List<Integer> sectionIndices = <span class="keyword">new</span> ArrayList<Integer>();

- String lastCreateDate = Helper.getFormatDate(tasks.get(<span class="number"></span>).getCreateTime());

- sectionIndices.add(<span class="number"></span>);

- <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number">1</span>; i < tasks.size(); i++) {

- String createDate = Helper.getFormatDate(tasks.get(i).getCreateTime());

- <span class="keyword">if</span> (!createDate.equals(lastCreateDate)) {

- lastCreateDate = createDate;

- sectionIndices.add(i);

- }

- }

- <span class="keyword">int</span>[] sections = <span class="keyword">new</span> <span class="keyword">int</span>[sectionIndices.size()];

- <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number"></span>; i < sectionIndices.size(); i++) {

- sections[i] = sectionIndices.get(i);

- }

- <span class="keyword">return</span> sections;

- }

- 
- <span class="keyword">private</span> String[] getSectionHeaders() {

- String[] sectionHeaders = <span class="keyword">new</span> String[sectionIndices.length];

- <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number"></span>; i < sectionIndices.length; i++) {

- sectionHeaders[i] = Helper.getFormatDate(tasks.get(sectionIndices[i]).getCreateTime());

- }

- <span class="keyword">return</span> sectionHeaders;

- }

- 
- <span class="annotation">@Override</span>

- <span class="keyword">public</span> <span class="keyword">int</span> getCount() {

- <span class="keyword">return</span> tasks.size();

- }

- 
- <span class="annotation">@Override</span>

- <span class="keyword">public</span> Object getItem(<span class="keyword">int</span> position) {

- <span class="keyword">return</span> tasks.get(position);

- }

- 
- <span class="annotation">@Override</span>

- <span class="keyword">public</span> <span class="keyword">long</span> getItemId(<span class="keyword">int</span> position) {

- <span class="keyword">return</span> tasks.get(position).getId();

- }

- 
- <span class="annotation">@Override</span>

- <span class="keyword">public</span> View getView(<span class="keyword">int</span> position, View convertView, ViewGroup parent) {

- ViewHolder viewHolder;

- <span class="keyword">if</span> (convertView == <span class="keyword">null</span>) {

- viewHolder = <span class="keyword">new</span> ViewHolder();

- convertView = layoutInflater.inflate(R.layout.task_item, <span class="keyword">null</span>);

- viewHolder.ivComplete = (ImageView)convertView.findViewById(R.id.ivComplete);

- viewHolder.tvTitle = (TextView) convertView.findViewById(R.id.tvTitle);

- viewHolder.tvCreateTime = (TextView) convertView.findViewById(R.id.tvCreateTime);

- convertView.setTag(viewHolder);

- } <span class="keyword">else</span> {

- viewHolder = (ViewHolder) convertView.getTag();

- }

- <span class="keyword">if</span>(<span class="string">&#8220;Y&#8221;</span>.equals(tasks.get(position).getFlagCompleted())){

- viewHolder.ivComplete.setVisibility(View.VISIBLE);

- viewHolder.tvCreateTime.setText(Helper.getFormatDate(tasks.get(position).getCompleteTime()));

- }<span class="keyword">else</span>{

- viewHolder.ivComplete.setVisibility(View.GONE);

- viewHolder.tvCreateTime.setText(Helper.getFormatDate(tasks.get(position).getCreateTime()));

- }

- viewHolder.tvTitle.setText(tasks.get(position).getTitle());

- 
- <span class="keyword">return</span> convertView;

- }

- 
- <span class="annotation">@Override</span>

- <span class="keyword">public</span> View getHeaderView(<span class="keyword">int</span> position, View convertView, ViewGroup parent) {

- HeaderViewHolder hvh;

- <span class="keyword">if</span>(convertView == <span class="keyword">null</span>){

- hvh = <span class="keyword">new</span> HeaderViewHolder();

- convertView = layoutInflater.inflate(R.layout.task_header, <span class="keyword">null</span>);

- hvh.tvHeader = (TextView) convertView.findViewById(R.id.tvHeader);

- convertView.setTag(hvh);

- }<span class="keyword">else</span>{

- hvh = (HeaderViewHolder)convertView.getTag();

- }

- hvh.tvHeader.setText(Helper.getFormatDate(tasks.get(position).getCreateTime()));

- <span class="keyword">return</span> convertView;

- }

- 
- <span class="annotation">@Override</span>

- <span class="keyword">public</span> <span class="keyword">long</span> getHeaderId(<span class="keyword">int</span> position) {

- <span class="keyword">return</span> Helper.changeStringDateToLong(Helper.getFormatDate(tasks.get(position).getCreateTime()));

- }

- 
- <span class="annotation">@Override</span>

- <span class="keyword">public</span> Object[] getSections() {

- <span class="comment">// TODO Auto-generated method stub</span>

- <span class="keyword">return</span> sectionHeaders;

- }

- 
- <span class="annotation">@Override</span>

- <span class="keyword">public</span> <span class="keyword">int</span> getPositionForSection(<span class="keyword">int</span> sectionIndex) {

- <span class="keyword">if</span> (sectionIndex >= sectionIndices.length) {

- sectionIndex = sectionIndices.length &#8211; <span class="number">1</span>;

- } <span class="keyword">else</span> <span class="keyword">if</span> (sectionIndex < <span class="number"></span>) {

- sectionIndex = <span class="number"></span>;

- }

- <span class="keyword">return</span> sectionIndices[sectionIndex];

- }

- 
- <span class="annotation">@Override</span>

- <span class="keyword">public</span> <span class="keyword">int</span> getSectionForPosition(<span class="keyword">int</span> position) {

- <span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number"></span>; i < sectionIndices.length; i++) {

- <span class="keyword">if</span> (position < sectionIndices[i]) {

- <span class="keyword">return</span> i &#8211; <span class="number">1</span>;

- }

- }

- <span class="keyword">return</span> sectionIndices.length &#8211; <span class="number">1</span>;

- }

- 
- <span class="keyword">class</span> ViewHolder {

- ImageView ivComplete;

- TextView tvTitle;

- TextView tvCreateTime;

- }

- 
- <span class="keyword">class</span> HeaderViewHolder{

- TextView tvHeader;

- }

- }
首先我们定义了下面两个数组,并且需要在构造的时候初始化它们:
**[java]** [view plain](http://blog.csdn.net/linmiansheng/article/details/20747775#)[copy](http://blog.csdn.net/linmiansheng/article/details/20747775#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/224769)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/224769/fork)
  <div>
    <embed id="ZeroClipboardMovie_4" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="18" height="18" align="middle" name="ZeroClipboardMovie_4">
    </embed>
  </div>
</div>
- <span class="keyword">private</span> <span class="keyword">int</span>[] sectionIndices;

- <span class="keyword">private</span> String[] sectionHeaders;

通过构造函数,我们可以发现,我们传到这个Adapter的数据源只有一个ArrayList,因为这才是真正的数据,我们分组也是基于这个数据源的。

但是我们要展现Header的,那么Header的数据是从哪里来的呢?所以我们在初始化的时候,就要去获得Header的数据。

大家可以看一下两个getSectionXXX的函数,可以看到在里面做了下面两件事情:

1)sectionIndices数组用来存放每一轮分组的第一个item的位置。

2)sectionHeaders数组用来存放每一个分组要展现的数据,因为能够分到同一组的item,它们肯定有一个相同且可以跟其它section区别开来的值,比如在上面,我是利用create_time来分成不同的组的,所以sectionHeaders存放的只是一个create_time。

不过大家在这里千万要注意:基于某个字段的分组,这个数据源必须是在这个字段上是有序的!

如果不是有序的,那么属于相同分组的数据就会被拆成几段了,而这个分组就没有意义了。

所以如果数据源不是有序的,那么我们在初始化获取分组的时候,也需要先将其变成有序的。

接下来,在我们平常继承BaseAdapter的情况下,我们都要去实现getView等功能,在上面也是一样的,但是我们这个Adapter还必须要实现另外两个接口:

1)StickyListHeadersAdapter

2)SectionIndexer

我们先来看看StickyListHeaderAdapter的定义:

**[java]** [view plain](http://blog.csdn.net/linmiansheng/article/details/20747775#)[copy](http://blog.csdn.net/linmiansheng/article/details/20747775#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/224769)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/224769/fork)
  <div>
    <embed id="ZeroClipboardMovie_5" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="18" height="18" align="middle" name="ZeroClipboardMovie_5">
    </embed>
  </div>
</div>
- <span class="keyword">public</span> <span class="keyword">interface</span> StickyListHeadersAdapter <span class="keyword">extends</span> ListAdapter {

- 
- View getHeaderView(<span class="keyword">int</span> position, View convertView, ViewGroup parent);

- 
- <span class="keyword">long</span> getHeaderId(<span class="keyword">int</span> position);

- }
这是开源库提供的接口,因为我们需要添加Header,所以我们必须在Adapter中也返回一个Header的View,这其实跟实现getView是一样的道理的,都挺好理解的。

所以在getHeaderView里面就会用到我们一开始新定义的那个task_header.xml了,同样的,为了实现优化,也会利用一个HeaderViewHolder。

另外一个接口就是SectionIndexer了,它有三个方法要实现,如下:

**[java]** [view plain](http://blog.csdn.net/linmiansheng/article/details/20747775#)[copy](http://blog.csdn.net/linmiansheng/article/details/20747775#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/224769)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/224769/fork)
  <div>
    <embed id="ZeroClipboardMovie_6" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="18" height="18" align="middle" name="ZeroClipboardMovie_6">
    </embed>
  </div>
</div>
- <span class="keyword">public</span> <span class="keyword">interface</span> SectionIndexer {

- 
- Object[] getSections();

- 
- <span class="keyword">int</span> getPositionForSection(<span class="keyword">int</span> sectionIndex);

- 
- <span class="keyword">int</span> getSectionForPosition(<span class="keyword">int</span> position);

- }

看代码的实现,可以发现:

getSections:返回的其实就是Header上面要展示的数据,在这里其实就是sectionHeaders了,存放的是create_time的数据。

getPositionForSection:返回的是这个section数据在List这个基础数据源中的位置,因为section中的数据其实也是从List中获取到的。

getSectionForPosition:则是通过在基础数据源List中的位置找出对应的Section中的数据,原因同上。

那么上面这两个函数的作用在哪?

大家有没有发现,当同一个分组的数据在滚动的时候,最上面的分组并不会变化,只有当滑到其它分组的时候,这个分组才会被新的分组给替换掉。这个效果实现的原理就在这里了,虽然我没有看过源代码,但是我认为,在每一个item滚动的时候,都会找出其对应的分组,然后显示在最上方,如果都是属于同一个分组的话,那么最上面的显示的当然一直都是这个分组对应的Header了。

综上所述,为了实现Sticky和分组的效果,我们就要在原来继承BaseAdapter的基础上再实现多两个接口,并实现对应的逻辑。

那么如何在Activity中使用呢?请看下面的代码:

在xml中定义:

**[html]** [view plain](http://blog.csdn.net/linmiansheng/article/details/20747775#)[copy](http://blog.csdn.net/linmiansheng/article/details/20747775#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/224769)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/224769/fork)
  <div>
    <embed id="ZeroClipboardMovie_7" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="18" height="18" align="middle" name="ZeroClipboardMovie_7">
    </embed>
  </div>
</div>
- <span class="tag"><</span><span class="tag-name">se.emilsjolander.stickylistheaders.StickyListHeadersListView</span>

- <span class="attribute">android:id</span>=<span class="attribute-value">&#8220;@+id/lvTasks&#8221;</span>

- <span class="attribute">android:layout_width</span>=<span class="attribute-value">&#8220;match_parent&#8221;</span>

- <span class="attribute">android:layout_height</span>=<span class="attribute-value">&#8220;match_parent&#8221;</span>

- <span class="attribute">android:background</span>=<span class="attribute-value">&#8220;@drawable/todo_bg&#8221;</span>

- <span class="attribute">android:clipToPadding</span>=<span class="attribute-value">&#8220;false&#8221;</span>

- <span class="attribute">android:divider</span>=<span class="attribute-value">&#8220;#44FFFFFF&#8221;</span>

- <span class="attribute">android:dividerHeight</span>=<span class="attribute-value">&#8220;1dp&#8221;</span>

- <span class="attribute">android:drawSelectorOnTop</span>=<span class="attribute-value">&#8220;true&#8221;</span>

- <span class="attribute">android:fastScrollEnabled</span>=<span class="attribute-value">&#8220;true&#8221;</span>

- <span class="attribute">android:overScrollMode</span>=<span class="attribute-value">&#8220;never&#8221;</span>

- <span class="attribute">android:padding</span>=<span class="attribute-value">&#8220;16dp&#8221;</span>

- <span class="attribute">android:scrollbarStyle</span>=<span class="attribute-value">&#8220;outsideOverlay&#8221;</span> <span class="tag">/></span>

在MainActivity中使用:

**[java]** [view plain](http://blog.csdn.net/linmiansheng/article/details/20747775#)[copy](http://blog.csdn.net/linmiansheng/article/details/20747775#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/224769)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/224769/fork)
  <div>
    <embed id="ZeroClipboardMovie_8" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="18" height="18" align="middle" name="ZeroClipboardMovie_8">
    </embed>
  </div>
</div>
- lvTasks = (StickyListHeadersListView) findViewById(R.id.lvTasks);

- taskAdapter = <span class="keyword">new</span> StickListTaskAdapter(<span class="keyword">this</span>, tasks);

- lvTasks.setAdapter(taskAdapter);

- lvTasks.setDrawingListUnderStickyHeader(<span class="keyword">true</span>);

- lvTasks.setAreHeadersSticky(<span class="keyword">true</span>);

- lvTasks.setOnItemLongClickListener(onItemLongClickListener);

- lvTasks.setOnItemClickListener(onItemClickListener);
而开源库中StickyListHeadersListView还提供了几个接口,可以让我们在Activity中去实现,不过这些就有待大家自己去慢慢学习了。
**[java]** [view plain](http://blog.csdn.net/linmiansheng/article/details/20747775#)[copy](http://blog.csdn.net/linmiansheng/article/details/20747775#)[![在CODE上查看代码片](https://code.csdn.net/assets/CODE_ico.png)](https://code.csdn.net/snippets/224769)[![派生到我的代码片](https://code.csdn.net/assets/ico_fork.svg)](https://code.csdn.net/snippets/224769/fork)
  <div>
    <embed id="ZeroClipboardMovie_9" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" type="application/x-shockwave-flash" width="18" height="18" align="middle" name="ZeroClipboardMovie_9">
    </embed>
  </div>
</div>
- <span class="keyword">public</span> <span class="keyword">class</span> StickyListHeadersListView <span class="keyword">extends</span> FrameLayout {

- 
- <span class="keyword">public</span> <span class="keyword">interface</span> OnHeaderClickListener {

- <span class="keyword">public</span> <span class="keyword">void</span> onHeaderClick(StickyListHeadersListView l, View header,

- <span class="keyword">int</span> itemPosition, <span class="keyword">long</span> headerId, <span class="keyword">boolean</span> currentlySticky);

- }

- 
- <span class="comment">/**</span>

- <span class="comment">     * Notifies the listener when the sticky headers top offset has changed.</span>

- <span class="comment">     */</span>

- <span class="keyword">public</span> <span class="keyword">interface</span> OnStickyHeaderOffsetChangedListener {

- <span class="comment">/**</span>

- <span class="comment">         * @param l      The view parent</span>

- <span class="comment">         * @param header The currently sticky header being offset.</span>

- <span class="comment">         *               This header is not guaranteed to have it&#8217;s measurements set.</span>

- <span class="comment">         *               It is however guaranteed that this view has been measured,</span>

- <span class="comment">         *               therefor you should user getMeasured* methods instead of</span>

- <span class="comment">         *               get* methods for determining the view&#8217;s size.</span>

- <span class="comment">         * @param offset The amount the sticky header is offset by towards to top of the screen.</span>

- <span class="comment">         */</span>

- <span class="keyword">public</span> <span class="keyword">void</span> onStickyHeaderOffsetChanged(StickyListHeadersListView l, View header, <span class="keyword">int</span> offset);

- }

- 
- <span class="comment">/**</span>

- <span class="comment">     * Notifies the listener when the sticky header has been updated</span>

- <span class="comment">     */</span>

- <span class="keyword">public</span> <span class="keyword">interface</span> OnStickyHeaderChangedListener {

- <span class="comment">/**</span>

- <span class="comment">         * @param l             The view parent</span>

- <span class="comment">         * @param header        The new sticky header view.</span>

- <span class="comment">         * @param itemPosition  The position of the item within the adapter&#8217;s data set of</span>

- <span class="comment">         *                      the item whose header is now sticky.</span>

- <span class="comment">         * @param headerId      The id of the new sticky header.</span>

- <span class="comment">         */</span>

- <span class="keyword">public</span> <span class="keyword">void</span> onStickyHeaderChanged(StickyListHeadersListView l, View header,

- <span class="keyword">int</span> itemPosition, <span class="keyword">long</span> headerId);

- 
- }
结束。

转自:http://blog.csdn.net/linmiansheng/article/details/20747775

💬 评论