CollectionView源码分析

  基本概念

  CollectionView是Google I/O 2014应用程序内置的控件,目的是以宫格样式显示不同分组的列表。

  CollectionView控件可以用来显示带不同标识头部的列表。除了可以给每个分组添加标识头部之外,还可以自定义每组元素的显示列数。AdapterView类必须实现CollectionViewCallbacks接口来定制头部和列表项的布局。然后,调用CollectionView的主类必须调用CollectionView.updateInventory(Inventory)方法来给所有需要填充的数据分组。每组元素按几列显示可以由InventoryGroup.setDisplayCols(int)方法设置。

  其中,Inventory类包含了所有需要填充数据的分组信息,InventoryGroup类则代表着某个分组,规定了组号,是否显示头部,头部标签,每行数据显示的列数,数据起始的索引,组中总的数据数。

  类关系图

  功能介绍

  CollectionView的主要方法有setCollectionAdapter(),updateInventory(),前者负责注入负责绘制头部和列表项的CollectionViewCallbacks接口实例,后者的作用是填充分好组的数据。填充好数据后,会调用notifyAdapterDataSetChanged()方法要求控件重新绘制。与普通的AdapterView直接调用notifyDataSetChanged()方法提醒数据源变化不同,notifyAdapterDataSetChanged()方法内部重新配置了一个MyListAdapter实例,MyListAdapter负责具体的视图渲染任务。

  到这里可能会有困惑?因为在实际使用CollectionView的过程中,我们编写了继承CursorAdapter(假设数据源是SQLite数据库)实现CollectionViewCallbacks接口的适配器类CollectionAdapter类,来负责渲染视图,那么CollectionView为什么将绘制任务交给MyListAdapter来做。

  其实,仔细研究代码就可以发现,我们编写的CollectionAdapter类只是可以绘制每个列表项元素和每个分组的头部元素,并没有办法绘制一整行列表项。MyListAdapter就是在CollectionAdapter的基础上进行组织,根据InventoryGroup.setDisplayCols(int)方法设置的列数来绘制一整行元素。

  MyListAdapter工作时,调用getRowViewType()方法得到当前行的视图类型,getRowViewType()方法接受一个用来保存当前行元数据的RowComputeResult实例。

  类RowComputeResult的代码如下:

  class RouComputeResult{

     int row;

  Boolean isHeader;

  int groupId;

  InventoryGroup group;

  int groupOffset;

  }

  虽然InventoryGroup类保存了某个分组的元数据,但是这个分组的元素可能需要多行显示,InventoryGroup类无法反映每一行的状况。所以,MyListAdapter类调用computeRowContent()方法计算每一行的数据应该如何绘制,计算结果保存在上述的RowComputeResult实例中。computeRowContent()方法不管计算哪一行的绘制数据,都需要遍历整个mInventroy.mGroups的分组信息集。

  MyListAdapter得到每行视图的类型后将调用getRowView()方法进行具体的绘制。getRowView()方法的回调栈如下:

  getRowView()

     ——makeRow()

         根据isHeader值调用

          ——mCallbacks.newCollectionHeaderView()

          ——makeItemRow()

        根据布局是否可以重用调用

     ——recycleItemRow()

  ——makeNewItemRow()

    ——getItemView()&& setupLayoutParams()

  到此,MyListAdapter将成功绘制各行元素。

  详细的活动图如下:

  结论

  CollectionView给出了借助ListView以宫格形式显示带有头部的列表的方案,优点是简单、直观,易于理解,易于使用。

  我个人认为CollectionView还有许多值得改进的地方,比如是否在分组的时候就计算好每组可能需要几行来展示,计算好每行元素的元数据?

时间: 2024-10-28 15:27:29

CollectionView源码分析的相关文章

【JUC】JDK1.8源码分析之ConcurrentHashMap(一)

一.前言 最近几天忙着做点别的东西,今天终于有时间分析源码了,看源码感觉很爽,并且发现ConcurrentHashMap在JDK1.8版本与之前的版本在并发控制上存在很大的差别,很有必要进行认真的分析,下面进行源码分析. 二.ConcurrentHashMap数据结构 之前已经提及过,ConcurrentHashMap相比HashMap而言,是多线程安全的,其底层数据与HashMap的数据结构相同,数据结构如下 说明:ConcurrentHashMap的数据结构(数组+链表+红黑树),桶中的结构

【JUC】JDK1.8源码分析之ConcurrentHashMap

一.前言 最近几天忙着做点别的东西,今天终于有时间分析源码了,看源码感觉很爽,并且发现ConcurrentHashMap在JDK1.8版本与之前的版本在并发控制上存在很大的差别,很有必要进行认真的分析,下面进行源码分析. 二.ConcurrentHashMap数据结构 之前已经提及过,ConcurrentHashMap相比HashMap而言,是多线程安全的,其底层数据与HashMap的数据结构相同,数据结构如下 说明:ConcurrentHashMap的数据结构(数组+链表+红黑树),桶中的结构

ConcurrentHashMap底层实现原理(JDK1.8)源码分析

ConcurrentHashMap数据结构 ConcurrentHashMap相比HashMap而言,是多线程安全的,其底层数据与HashMap的数据结构相同,数据结构如下: 说明:ConcurrentHashMap的数据结构(数组+链表+红黑树),桶中的结构可能是链表,也可能是红黑树,红黑树是为了提高查找效率. ConcurrentHashMap源码分析 1.类的继承关系 public class ConcurrentHashMap<K,V> extends AbstractMap<K

TeamTalk源码分析之login_server

login_server是TeamTalk的登录服务器,负责分配一个负载较小的MsgServer给客户端使用,按照新版TeamTalk完整部署教程来配置的话,login_server的服务端口就是8080,客户端登录服务器地址配置如下(这里是win版本客户端): 1.login_server启动流程 login_server的启动是从login_server.cpp中的main函数开始的,login_server.cpp所在工程路径为server\src\login_server.下表是logi

Android触摸屏事件派发机制详解与源码分析二(ViewGroup篇)

1 背景 还记得前一篇<Android触摸屏事件派发机制详解与源码分析一(View篇)>中关于透过源码继续进阶实例验证模块中存在的点击Button却触发了LinearLayout的事件疑惑吗?当时说了,在那一篇咱们只讨论View的触摸事件派发机制,这个疑惑留在了这一篇解释,也就是ViewGroup的事件派发机制. PS:阅读本篇前建议先查看前一篇<Android触摸屏事件派发机制详解与源码分析一(View篇)>,这一篇承接上一篇. 关于View与ViewGroup的区别在前一篇的A

HashMap与TreeMap源码分析

1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Java这么久,也写过一些小项目,也使用过TreeMap无数次,但到现在才明白它的实现原理).因此本着"不要重复造轮子"的思想,就用这篇博客来记录分析TreeMap源码的过程,也顺便瞅一瞅HashMap. 2. 继承结构 (1) 继承结构 下面是HashMap与TreeMap的继承结构: pu

Linux内核源码分析--内核启动之(5)Image内核启动(rest_init函数)(Linux-3.0 ARMv7)【转】

原文地址:Linux内核源码分析--内核启动之(5)Image内核启动(rest_init函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://blog.chinaunix.net/uid-25909619-id-4938395.html 前面粗略分析start_kernel函数,此函数中基本上是对内存管理和各子系统的数据结构初始化.在内核初始化函数start_kernel执行到最后,就是调用rest_init函数,这个函数的主要使命就是创建并启动内核线

Spark的Master和Worker集群启动的源码分析

基于spark1.3.1的源码进行分析 spark master启动源码分析 1.在start-master.sh调用master的main方法,main方法调用 def main(argStrings: Array[String]) { SignalLogger.register(log) val conf = new SparkConf val args = new MasterArguments(argStrings, conf) val (actorSystem, _, _, _) =

Solr4.8.0源码分析(22)之 SolrCloud的Recovery策略(三)

Solr4.8.0源码分析(22)之 SolrCloud的Recovery策略(三) 本文是SolrCloud的Recovery策略系列的第三篇文章,前面两篇主要介绍了Recovery的总体流程,以及PeerSync策略.本文以及后续的文章将重点介绍Replication策略.Replication策略不但可以在SolrCloud中起到leader到replica的数据同步,也可以在用多个单独的Solr来实现主从同步.本文先介绍在SolrCloud的leader到replica的数据同步,下一篇