Android 开源库StickyListHeadersListView来实现ListView列表分组效果
项目中有一新的需求,要求能像一些Android机带“联系人列表”一样,数据可以自动分组,且在列表滑动过程中,列表头固定在顶部,效果图如下:
下面就带大家实现上面的效果, 首先,我们要介绍的一个重要的开源库:StickyListHeaders,它的Github地址是:https://github.com/emilsjolander/StickyListHeaders,
使用该库,可以更加方便的实现ListView数据分组,且Header固定在顶部。
首先,把github上的项目下载下来,加压后,可看到其中有一个library库,我们需要将该库(Module)导入到新建的项目中,并在自己的Module引入该Library。
项目建成后,开始使用该库进行开发:
1. 布局中引入StickyListHeadersListView:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"> <se.emilsjolander.stickylistheaders.StickyListHeadersListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:cacheColorHint="#00000000"
android:clipToPadding="false"
android:drawSelectorOnTop="true"
android:fastScrollEnabled="true"
android:listSelector="#00000000"
android:overScrollMode="never"
android:scrollbarStyle="outsideOverlay" /> </RelativeLayout>
2. 创建要显示的数据实体
public class LangyaSimple { private String id;
private String proj_id;
private String title;
private String desc;
private String project_title; public LangyaSimple(String id, String proj_id, String title, String desc, String project_title) {
this.id = id;
this.proj_id = proj_id;
this.title = title;
this.desc = desc;
this. = project_title;
} public String getId() {
return id;
} public void setId(String id) {
this.id = id;
} public String getProj_id() {
return proj_id;
} public void setProj_id(String proj_id) {
this.proj_id = proj_id;
} public String getTitle() {
return title;
} public void setTitle(String title) {
this.title = title;
} public String getDesc() {
return desc;
} public void setDesc(String desc) {
this.desc = desc;
} public String getProject_title() {
return project_title;
} public void setProject_title(String project_title) {
this.project_title = project_title;
} @Override
public String toString() {
return "LangyaSimple{" +
"id='" + id + '\'' +
", proj_id='" + proj_id + '\'' +
", title='" + title + '\'' +
", desc='" + desc + '\'' +
", project_title='" + project_title + '\'' +
'}';
}
}
注: id是data数据的id,proj_id是该数据所属的组的意思,proj_title是该组的名字;
3. 定义StickyListHeadersListView要显示的适配器:
import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView; import java.util.List; import se.emilsjolander.stickylistheaders.StickyListHeadersAdapter; public class LangyaAdapter extends BaseAdapter implements StickyListHeadersAdapter { private LayoutInflater inflater; private List<LangyaSimple> mPlanDetails; public LangyaAdapter(Activity context, List<LangyaSimple> mPlanDetails) {
inflater = LayoutInflater.from(context);
this.mPlanDetails = mPlanDetails; } @Override
public int getCount() {
return mPlanDetails.size();
} @Override
public Object getItem(int position) {
return mPlanDetails.get(position);
} @Override
public long getItemId(int position) {
return position;
} @Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder; if (convertView == null) {
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.list_item_proj_plan, parent, false); holder.img_plan = (ImageView) convertView.findViewById(R.id.img_plan); holder.text_plan_name = (TextView) convertView.findViewById(R.id.text_plan_name);
holder.text_plan_info = (TextView) convertView.findViewById(R.id.text_plan_info); convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
} LangyaSimple planDetail = this.mPlanDetails.get(position); if (planDetail != null) { // ImageLoaderUtil.getInstance().displayListItemImage(imgUrl, holder.img_plan);
holder.text_plan_name.setText(planDetail.getTitle());
holder.text_plan_info.setText(planDetail.getDesc());
} return convertView;
} @Override
public View getHeaderView(int position, View convertView, ViewGroup parent) {
HeaderViewHolder holder;
if (convertView == null) {
holder = new HeaderViewHolder();
convertView = inflater.inflate(R.layout.proj_plans_header, parent, false);
holder.text = (TextView) convertView.findViewById(R.id.text1);
convertView.setTag(holder);
} else {
holder = (HeaderViewHolder) convertView.getTag();
}
//set proj_plans_header text as first char in name
String headerText = this.mPlanDetails.get(position).getProject_title();
holder.text.setText(headerText);
return convertView;
} @Override
public long getHeaderId(int position) {
//return the first character of the country as ID because this is what headers are based upon
return Long.parseLong(this.mPlanDetails.get(position).getProj_id());
} class HeaderViewHolder {
TextView text;
} class ViewHolder {
ImageView img_plan; TextView text_plan_name; TextView text_plan_info;
}
}
适配器是List数据显示最重要的部分,为了实现数据分组,该适配器必须要实现StickyListHeadersAdapter接口,并重写其中的getHeaderView(int position, View convertView, ViewGroup parent);和long getHeaderId(int position);方法。
说明:
getHeaderView方法指定了Header的View的显示;
getHeaderId决定header出现的时机,如果当前的headerid和前一个headerid不同时,就会显示。
4. 定义数据显示的Activity:
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView; import java.util.ArrayList;
import java.util.List; import se.emilsjolander.stickylistheaders.StickyListHeadersListView; public class MainActivity extends Activity { public StickyListHeadersListView list; private LangyaAdapter langyaAdapter; private List<LangyaSimple> mLangyaDatas; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); list = (StickyListHeadersListView) findViewById(R.id.list);
mLangyaDatas = new ArrayList<LangyaSimple>(); initDatas(); list.setOnItemClickListener(new OnPlanItemClick());
list.setOnItemLongClickListener(new OnPlanItemLongClick()); langyaAdapter = new LangyaAdapter(this, mLangyaDatas);
list.setAdapter(langyaAdapter); } private void updateData() { if (langyaAdapter != null && mLangyaDatas != null) { langyaAdapter.notifyDataSetChanged();
}
} private class OnPlanItemClick implements AdapterView.OnItemClickListener { @Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
LangyaSimple oLangyaSimple = (LangyaSimple) parent.getAdapter().getItem(
position);
Log.e("tag", oLangyaSimple.toString());
}
} private class OnPlanItemLongClick implements AdapterView.OnItemLongClickListener { @Override
public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { LangyaSimple oLangyaSimple = mLangyaDatas.get(position); Log.e("tag", oLangyaSimple.toString()); mLangyaDatas.remove(oLangyaSimple); updateData(); return true;
}
} private void initDatas() { mLangyaDatas.add(new LangyaSimple("1", "1", "无缘公子", "无缘公子无缘公子无缘公子无缘公子", "公子榜"));
mLangyaDatas.add(new LangyaSimple("2", "1", "无请公子", "无请公子无请公子无请公子无请公子", "公子榜"));
mLangyaDatas.add(new LangyaSimple("3", "1", "无名公子", "无名公子无名公子无名公子无名公子", "公子榜"));
mLangyaDatas.add(new LangyaSimple("4", "1", "无非公子", "无非公子无非公子无非公子无非公子", "公子榜"));
mLangyaDatas.add(new LangyaSimple("5", "1", "无能公子", "无能公子无能公子无能公子无能公子", "公子榜")); mLangyaDatas.add(new LangyaSimple("6", "2", "最无情", "最无情最无情最无情最无情最无情", "高手榜"));
mLangyaDatas.add(new LangyaSimple("7", "2", "最无情", "最无情最无情最无情最无情最无情", "高手榜"));
mLangyaDatas.add(new LangyaSimple("8", "2", "最无情", "最无情最无情最无情最无情最无情", "高手榜"));
mLangyaDatas.add(new LangyaSimple("9", "2", "最无情", "最无情最无情最无情最无情最无情", "高手榜"));
mLangyaDatas.add(new LangyaSimple("10", "2", "最无情", "最无情最无情最无情最无情最无情", "高手榜")); mLangyaDatas.add(new LangyaSimple("11", "3", "情殇", "情殇情殇情殇情殇情殇情殇情殇", "美人榜"));
mLangyaDatas.add(new LangyaSimple("12", "3", "情殇", "情殇情殇情殇情殇情殇情殇情殇", "美人榜"));
mLangyaDatas.add(new LangyaSimple("13", "3", "情殇", "情殇情殇情殇情殇情殇情殇情殇", "美人榜"));
mLangyaDatas.add(new LangyaSimple("14", "3", "情殇", "情殇情殇情殇情殇情殇情殇情殇", "美人榜"));
mLangyaDatas.add(new LangyaSimple("15", "3", "情殇", "情殇情殇情殇情殇情殇情殇情殇", "美人榜"));
}
}
该Activity实现了较多的方法,1. 数据显示, 2. 列表的单机事件, 3. 列表的长按事件, 4. 数据更新等;
有个地方需要着重说明,那就是在初始化数据时,数据必须proj_id必须按分组排列,即,不要将proj_id不同的数据参差着放在集合中,否则容易造成列表显示多组相同组名的数据。
对StickyListHeadersListView其余的操作(点击、长按),和普通的ListView一致,包括在xml中设置的属性也是一致的。
如此这般,便可实现上述的效果了!
源码下载地址(免费):http://download.csdn.net/detail/zuiwuyuan/9274693
Android 开源库StickyListHeadersListView来实现ListView列表分组效果的更多相关文章
- GitHub上排名前100的Android开源库介绍(来自github)
本项目主要对目前 GitHub 上排名前 100 的 Android 开源库进行简单的介绍,至于排名完全是根据 GitHub 搜索 Java 语言选择 (Best Match) 得到的结果,然后过滤了 ...
- GitHub Top 100的Android开源库
摘要: 本项目主要对目前 GitHub 上排名前 100 的 Android 开源库进行简单的介绍, 至于排名完全是根据GitHub搜索Java语言选择「Best M... 本项目主要对目前 GitH ...
- 我的Android进阶之旅】GitHub 上排名前 100 的 Android 开源库进行简单的介绍
GitHub Android Libraries Top 100 简介 本文转载于:https://github.com/Freelander/Android_Data/blob/master/And ...
- <Android开源库 ~ 1> GitHub Android Libraries Top 100 简介
转载自GitHub Android Libraries Top 100 简介 本项目主要对目前 GitHub 上排名前 100 的 Android 开源库进行简单的介绍, 至于排名完全是根据 GitH ...
- GitHub上排名前100的Android开源库介绍
GitHub上排名前100的Android开源库介绍 文章来源: http://www.open-open.com/news/view/1587067#6734290-qzone-1-31660-bf ...
- 【Java&Android开源库代码分析】のandroid-async-http の开盘
在<[Java&Android开源库代码剖析]のandroid-smart-image-view>一文中我们提到了android-async-http这个开源库,本文正 ...
- Android 开源库和项目 3
Android 开源库和项目 Android 开源库和项目 2 1.Matisse Android 图片选择器 -- 知乎开源 github 地址:https://github.com/zhihu/M ...
- Android 开源库获取途径整理
介绍眼下收藏 Android 开源库比較多的 GitHub 项目.站点.Twitter.App 及怎样获取最新的 Android 开源库. 微信号: 1. GitHub Android 开源项目汇总 ...
- 100个Github上Android开源库
项目名称 项目简介 1. react-native 这个是 Facebook 在 React.js Conf 2015 大会上推出的基于 JavaScript 的开源框架 React Native, ...
随机推荐
- org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.hs.model.StudentModel]: No default constructor found; nested exception is java.lang.NoSuchMethodException: c
root cause org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [c ...
- Ocelot(二)- 请求聚合
原文:Ocelot(二)- 请求聚合 Ocelot(二)- 请求聚合与负载均衡 作者:markjiang7m2 原文地址:https://www.cnblogs.com/markjiang7m2/p/ ...
- Struts_改写客户列表练习
1.CustomerAction修改放入ActionContext 2.list.jsp使用struts标签库
- pytest 用 @pytest.mark.usefixtures("fixtureName")或@pytest.fixture(scope="function", autouse=True)装饰,实现类似setup和TearDown的功能
conftest.py import pytest @pytest.fixture(scope="class") def class_auto(): print("&qu ...
- Thinkphp 调试方法
1.入口文件index.php配置APP_DEBUG,能直接发现页面上的错误 define('APP_DEBUG',True); 2.配置页面调试SHOW_PAGE_TRACE,可以在config里面 ...
- line-height的用法(一)
行高”顾名思意指一行文字的高度.具体来说是指两行文字间基线之间的距离. 从上到下四条线分别是顶线.中线.基线.底线,很像才学英语字母时的四线三格,我们知道vertical-align属性中有top.m ...
- const、引用与指针
前提 我们忽略掉了相同类型是否可以赋值的情况(我到现在的学习里都还可以相互赋值),以及类型兼容的情况.只考虑const.&.*等修饰符带来的影响 类型兼容: 强制类型转换 基类与子类间的兼容 ...
- DateTimeFormatter
//解析日期 String dateStr= "2018年12月18日"; DateTimeFormatter formatter = DateTimeFormatter.ofPa ...
- 深入探索WebSockets
WebSockets简介 在2008年中期,开发人员Michael Carter和Ian Hickson特别敏锐地感受到Comet在实施任何真正强大的东西时所带来的痛苦和局限. 通过在IRC和W3C邮 ...
- NOIP模拟 17.8.15
NOIP模拟17.8.15 A 债务文件名 输入文件 输出文件 时间限制 空间限制debt.pas/c/cpp debt.in debt.out 1s 128MB[题目描述]小 G 有一群好朋友,他们 ...