项目中有一新的需求,要求能像一些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