最近笔者在做一个项目。需求里面有一个效果是一个ListView:按带日期标题(格式:yyyy-MM-dd)分类,item为(格式:HH:mm:ss),并且在滑动过程中,当日期标题滑动到顶部的时候,进行悬浮;下一个日期标题到达顶部的时候把前一个header顶上去,废话不多少,先上效果图。
首先是需求想要实现的效果,仿虎扑体育。
然后是笔者实现的效果(因为项目还未上线,显示内容涉及到公司一些东西,因此显示的内容就马赛克了一下,不好意思):
接下来说一下,这种效果需要实现的难点吧:
1.自定义listview,实现sectionItem和contentItem的区分,并将sectionItemj进行滑动监听,在顶部进行悬浮,并进行悬浮在顶部的阴影绘制(为了有悬浮的视觉效果真实感)。(注:该自定义view参照Github上开源项目PinnedSectionListView。在末尾:笔者会贴出带下拉刷新、上拉加载的listview和不带刷新的listview的demo.在这里自定义控件的细节就不做说明了,demo里面有详细的中文注释,有兴趣的童鞋可以看看,相信大家都能看懂。O(∩_∩)O~)
这里笔者重点分享一下如何把一个arraylist集合里面的所有数据按照某一固定的类型添加分类(分组),最后将所有数据按照分类进行整理,遍历显示。
1、ArrayList集合里面的数据:
因为这边从后台接收到的item的json数据日期格式为:yyyy-MM-dd HH:mm:ss;按照(yyyy-MM-dd为header,滑动到顶部要进行悬浮),(HH:mm:ss为正常的item,滑动到顶部不需要悬浮)进行重新分类。
2、实现思路:
其实实现也很简单!这里要利用到Map的特性。没错,猜大家已经想到了。key,String,键值对的形式来实现。具体:ArrayList里面的每条数据都含有yyyy-MM-dd HH:mm:ss。因此,我们把yyyy-MM-dd设成Map的key,凡是属于这一天的data都放在这个key下面。那么ArrayList所有的data都按照日期yyyy-MM-dd进行了分类。但是Map没办法在listview里面setAdapter呀。到了这一步就好办了,那就把Map(含Key)所有的数据都遍历出来,重新加入到一个ArrayList里面。
3、关键代码:
首先,是时间转换为yyyy-MM-dd和HH:mm:ss的工具类:
/** * 返回 yyyy-MM-dd * * @param String 参数为String类型yyyy-MM-dd HH:mm:ss * @return 返回 yyyy-MM-dd * @throws ParseException */ public static String exchangeStringDate(String date) throws ParseException { if (date != null && date.length() > 10) { String result = date.substring(0, 10); return result; }else{ return null; } } /** * 返回HH:mm:ss * * @param String 参数为String类型 * @return 返回HH:mm:ss * @throws ParseException */ public static String exchangeStringTime(String date) throws ParseException { if (date != null && date.length() > 10) { String result = date.substring(10, date.length()); return result; }else{ return null; } }
/** * 通过HashMap键值对的特性,将ArrayList的数据进行分组,返回带有分组Header的ArrayList。 * @param details 从后台接受到的ArrayList的数据,其中日期格式为:yyyy-MM-dd HH:mm:ss * @return list 返回的list是分类后的包含header(yyyy-MM-dd)和item(HH:mm:ss)的ArrayList */ @SuppressWarnings({ "rawtypes", "unchecked" }) public static ArrayList<PinnedSectionBean> getData(List<WarnDetail> details){ //最后我们要返回带有分组的list,初始化 ArrayList<PinnedSectionBean> list = new ArrayList<PinnedSectionBean>(); //时间转换的util类 TimeManagement management = new TimeManagement(); //WarnDetail作为key是yyyy-MM-dd格式,List<WarnDetail>是对应的值是HH:mm:ss格式 Map<WarnDetail, List<WarnDetail>> map = new HashMap<WarnDetail, List<WarnDetail>>(); //按照warndetail里面的时间进行分类 WarnDetail detail = new WarnDetail(); for (int i = 0; i < details.size(); i++) { try { String key = management.exchangeStringDate(details.get(i).getAddtime()) ; if (detail.getAddtime() != null && !"".equals(detail.getAddtime())) { //判断这个Key对象有没有生成,保证是唯一对象.如果第一次没有生成,那么new一个对象,之后同组的其他item都指向这个key boolean b = !key.equals(detail.getAddtime().toString()); if (b) { detail = new WarnDetail(); } } detail.setAddtime(key); //把属于当天yyyy-MM-dd的时间HH:mm:ss全部指向这个key List<WarnDetail> warnDetails = map.get(detail); //判断这个key对应的值有没有初始化,若第一次进来,这new一个arryalist对象,之后属于这一天的item都加到这个集合里面 if (warnDetails == null) { warnDetails = new ArrayList<WarnDetail>(); } String time = details.get(i).getAddtime(); time = management.exchangeStringTime(time); details.get(i).setAddtime(time); warnDetails.add(details.get(i)); map.put(detail, warnDetails); } catch (ParseException e) { e.printStackTrace(); } } //用迭代器遍历map添加到list里面 Iterator iterator = map.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = (Entry) iterator.next(); WarnDetail key = (WarnDetail) entry.getKey(); //我们的key(yyyy-MM-dd)作为标题.类别属于SECTION list.add(new PinnedSectionBean(SECTION, key)); List<WarnDetail> li = (List<WarnDetail>) entry.getValue(); for (WarnDetail warnDetail : li) { //对应的值(HH:mm:ss)作为标题下的item,类别属于ITEM list.add(new PinnedSectionBean(ITEM, warnDetail)); } } //把分好类的hashmap添加到list里面便于显示 return list; }
备注:其中WarnDetail是我们的ListView显示item的实体类,大家可以根据自己具体的项目进行替换.其次,分类的类别是灵活多变的,可以按照时间分类,也可以按照地点分类,或者按照WarnDetail里面某一项数据进行分类.只要掌握Map键值对进行分类的思想,即可进行拓展延伸.
特别提醒:对于item的点击事件:关于setItemOnclickListener中postion的问题,除了arg2-1 = postion以外,记得数据data是分类转换后的real_data哈.否则会有脚标越界的Exception.和点击item跳转错误的bug.
最后,是笔者做的另外一个效果图,按照地点分类的list.贴上来给大家参考一下.(*^__^*)
demo效果图:
友情提示:如果你还想再对list里面的数据进行排序,可以用Comparator进行排序.笔者就不再重复了,网上有很多相关资料介绍,有需求的童鞋可以Google一下.
第一次发布博客,稍微有点紧张,如有有纰漏,欢迎各位看官指出,大家一起相互学习,有问题的话,欢迎留言,我会一一给大家回复的.