利用StickyListHeaders来实现ListView的分组实现

分类: Android Demo 2014-03-08 17:37 244人阅读 评论(1) 收藏 举报
StickyListHeaders Android SectionIndexer ListView分组

很多情况下, 我们想要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 copy print ?
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:background="@drawable/header_selector" >
  6. <TextView
  7. android:id="@+id/tvHeader"
  8. android:layout_width="wrap_content"
  9. android:layout_height="match_parent"
  10. android:layout_gravity="start|left"
  11. android:padding="5dp"
  12. android:textColor="@android:color/white"
  13. android:textSize="17sp"
  14. android:textStyle="bold" />
  15. </RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/header_selector" ><TextViewandroid:id="@+id/tvHeader"android:layout_width="wrap_content"android:layout_height="match_parent"android:layout_gravity="start|left"android:padding="5dp"android:textColor="@android:color/white"android:textSize="17sp"android:textStyle="bold" /></RelativeLayout>

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

1.2)task_item.xml

[html] view plain copy print ?
  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="32dp"
  5. android:descendantFocusability="blocksDescendants"
  6. android:padding="5dip">
  7. <ImageView
  8. android:padding="5dp"
  9. android:layout_centerVertical="true"
  10. android:id="@+id/ivComplete"
  11. android:layout_width="wrap_content"
  12. android:layout_height="match_parent"
  13. android:layout_alignParentLeft="true"
  14. android:layout_alignParentTop="true"
  15. android:contentDescription="@string/imageview_contentdesc"
  16. android:src="@drawable/handdraw_tick"
  17. android:visibility="gone" />
  18. <TextView
  19. android:id="@+id/tvTitle"
  20. android:layout_width="wrap_content"
  21. android:layout_height="match_parent"
  22. android:layout_toRightOf="@+id/ivComplete"
  23. android:gravity="left|center_vertical"
  24. android:padding="5dp"
  25. android:textSize="20sp" />
  26. </RelativeLayout>
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="32dp"android:descendantFocusability="blocksDescendants"android:padding="5dip"><ImageViewandroid:padding="5dp"android:layout_centerVertical="true"android:id="@+id/ivComplete"android:layout_width="wrap_content"android:layout_height="match_parent"android:layout_alignParentLeft="true"android:layout_alignParentTop="true"android:contentDescription="@string/imageview_contentdesc"android:src="@drawable/handdraw_tick"android:visibility="gone" /><TextViewandroid:id="@+id/tvTitle"android:layout_width="wrap_content"android:layout_height="match_parent"android:layout_toRightOf="@+id/ivComplete"android:gravity="left|center_vertical"android:padding="5dp"android:textSize="20sp" />
</RelativeLayout>

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

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

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

[java] view plain copy print ?
  1. public class StickListTaskAdapter extends BaseAdapter
  2. implements SectionIndexer, StickyListHeadersAdapter{
  3. private LayoutInflater layoutInflater;
  4. private List<TodoTask> tasks;
  5. private int[] sectionIndices;
  6. private String[] sectionHeaders;
  7. public StickListTaskAdapter(Context context, List<TodoTask> tasks) {
  8. layoutInflater = LayoutInflater.from(context);
  9. this.tasks = tasks;
  10. sectionIndices = getSectionIndices();
  11. sectionHeaders = getSectionHeaders();
  12. }
  13. public void refresh(List<TodoTask> tasks){
  14. this.tasks = tasks;
  15. sectionIndices = getSectionIndices();
  16. sectionHeaders = getSectionHeaders();
  17. notifyDataSetChanged();
  18. }
  19. private int[] getSectionIndices() {
  20. List<Integer> sectionIndices = new ArrayList<Integer>();
  21. String lastCreateDate = Helper.getFormatDate(tasks.get(0).getCreateTime());
  22. sectionIndices.add(0);
  23. for (int i = 1; i < tasks.size(); i++) {
  24. String createDate = Helper.getFormatDate(tasks.get(i).getCreateTime());
  25. if (!createDate.equals(lastCreateDate)) {
  26. lastCreateDate = createDate;
  27. sectionIndices.add(i);
  28. }
  29. }
  30. int[] sections = new int[sectionIndices.size()];
  31. for (int i = 0; i < sectionIndices.size(); i++) {
  32. sections[i] = sectionIndices.get(i);
  33. }
  34. return sections;
  35. }
  36. private String[] getSectionHeaders() {
  37. String[] sectionHeaders = new String[sectionIndices.length];
  38. for (int i = 0; i < sectionIndices.length; i++) {
  39. sectionHeaders[i] = Helper.getFormatDate(tasks.get(sectionIndices[i]).getCreateTime());
  40. }
  41. return sectionHeaders;
  42. }
  43. @Override
  44. public int getCount() {
  45. return tasks.size();
  46. }
  47. @Override
  48. public Object getItem(int position) {
  49. return tasks.get(position);
  50. }
  51. @Override
  52. public long getItemId(int position) {
  53. return tasks.get(position).getId();
  54. }
  55. @Override
  56. public View getView(int position, View convertView, ViewGroup parent) {
  57. ViewHolder viewHolder;
  58. if (convertView == null) {
  59. viewHolder = new ViewHolder();
  60. convertView = layoutInflater.inflate(R.layout.task_item, null);
  61. viewHolder.ivComplete = (ImageView)convertView.findViewById(R.id.ivComplete);
  62. viewHolder.tvTitle = (TextView) convertView.findViewById(R.id.tvTitle);
  63. viewHolder.tvCreateTime = (TextView) convertView.findViewById(R.id.tvCreateTime);
  64. convertView.setTag(viewHolder);
  65. } else {
  66. viewHolder = (ViewHolder) convertView.getTag();
  67. }
  68. if("Y".equals(tasks.get(position).getFlagCompleted())){
  69. viewHolder.ivComplete.setVisibility(View.VISIBLE);
  70. viewHolder.tvCreateTime.setText(Helper.getFormatDate(tasks.get(position).getCompleteTime()));
  71. }else{
  72. viewHolder.ivComplete.setVisibility(View.GONE);
  73. viewHolder.tvCreateTime.setText(Helper.getFormatDate(tasks.get(position).getCreateTime()));
  74. }
  75. viewHolder.tvTitle.setText(tasks.get(position).getTitle());
  76. return convertView;
  77. }
  78. @Override
  79. public View getHeaderView(int position, View convertView, ViewGroup parent) {
  80. HeaderViewHolder hvh;
  81. if(convertView == null){
  82. hvh = new HeaderViewHolder();
  83. convertView = layoutInflater.inflate(R.layout.task_header, null);
  84. hvh.tvHeader = (TextView) convertView.findViewById(R.id.tvHeader);
  85. convertView.setTag(hvh);
  86. }else{
  87. hvh = (HeaderViewHolder)convertView.getTag();
  88. }
  89. hvh.tvHeader.setText(Helper.getFormatDate(tasks.get(position).getCreateTime()));
  90. return convertView;
  91. }
  92. @Override
  93. public long getHeaderId(int position) {
  94. return Helper.changeStringDateToLong(Helper.getFormatDate(tasks.get(position).getCreateTime()));
  95. }
  96. @Override
  97. public Object[] getSections() {
  98. // TODO Auto-generated method stub
  99. return sectionHeaders;
  100. }
  101. @Override
  102. public int getPositionForSection(int sectionIndex) {
  103. if (sectionIndex >= sectionIndices.length) {
  104. sectionIndex = sectionIndices.length - 1;
  105. } else if (sectionIndex < 0) {
  106. sectionIndex = 0;
  107. }
  108. return sectionIndices[sectionIndex];
  109. }
  110. @Override
  111. public int getSectionForPosition(int position) {
  112. for (int i = 0; i < sectionIndices.length; i++) {
  113. if (position < sectionIndices[i]) {
  114. return i - 1;
  115. }
  116. }
  117. return sectionIndices.length - 1;
  118. }
  119. class ViewHolder {
  120. ImageView ivComplete;
  121. TextView tvTitle;
  122. TextView tvCreateTime;
  123. }
  124. class HeaderViewHolder{
  125. TextView tvHeader;
  126. }
  127. }
public class StickListTaskAdapter extends BaseAdapter implements SectionIndexer, StickyListHeadersAdapter{private LayoutInflater layoutInflater;private List<TodoTask> tasks;private int[] sectionIndices;private String[] sectionHeaders;public StickListTaskAdapter(Context context, List<TodoTask> tasks) {layoutInflater = LayoutInflater.from(context);this.tasks = tasks;sectionIndices = getSectionIndices();sectionHeaders = getSectionHeaders();}public void refresh(List<TodoTask> tasks){this.tasks = tasks;sectionIndices = getSectionIndices();sectionHeaders = getSectionHeaders();notifyDataSetChanged();}private int[] getSectionIndices() {List<Integer> sectionIndices = new ArrayList<Integer>();String lastCreateDate = Helper.getFormatDate(tasks.get(0).getCreateTime());sectionIndices.add(0);for (int i = 1; i < tasks.size(); i++) {String createDate = Helper.getFormatDate(tasks.get(i).getCreateTime());if (!createDate.equals(lastCreateDate)) {lastCreateDate = createDate;sectionIndices.add(i);}}int[] sections = new int[sectionIndices.size()];for (int i = 0; i < sectionIndices.size(); i++) {sections[i] = sectionIndices.get(i);}return sections;}private String[] getSectionHeaders() {String[] sectionHeaders = new String[sectionIndices.length];for (int i = 0; i < sectionIndices.length; i++) {sectionHeaders[i] = Helper.getFormatDate(tasks.get(sectionIndices[i]).getCreateTime());}return sectionHeaders;}@Overridepublic int getCount() {return tasks.size();}@Overridepublic Object getItem(int position) {return tasks.get(position);}@Overridepublic long getItemId(int position) {return tasks.get(position).getId();}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {ViewHolder viewHolder;if (convertView == null) {viewHolder = new ViewHolder();convertView = layoutInflater.inflate(R.layout.task_item, null);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);} else {viewHolder = (ViewHolder) convertView.getTag();}          if("Y".equals(tasks.get(position).getFlagCompleted())){viewHolder.ivComplete.setVisibility(View.VISIBLE);viewHolder.tvCreateTime.setText(Helper.getFormatDate(tasks.get(position).getCompleteTime()));}else{viewHolder.ivComplete.setVisibility(View.GONE);viewHolder.tvCreateTime.setText(Helper.getFormatDate(tasks.get(position).getCreateTime()));}viewHolder.tvTitle.setText(tasks.get(position).getTitle());return convertView;}@Overridepublic View getHeaderView(int position, View convertView, ViewGroup parent) {HeaderViewHolder hvh;if(convertView == null){hvh = new HeaderViewHolder();convertView = layoutInflater.inflate(R.layout.task_header, null);hvh.tvHeader = (TextView) convertView.findViewById(R.id.tvHeader);convertView.setTag(hvh);}else{hvh = (HeaderViewHolder)convertView.getTag();}hvh.tvHeader.setText(Helper.getFormatDate(tasks.get(position).getCreateTime()));return convertView;}@Overridepublic long getHeaderId(int position) {return Helper.changeStringDateToLong(Helper.getFormatDate(tasks.get(position).getCreateTime()));}@Overridepublic Object[] getSections() {// TODO Auto-generated method stubreturn sectionHeaders;}@Overridepublic int getPositionForSection(int sectionIndex) {if (sectionIndex >= sectionIndices.length) {sectionIndex = sectionIndices.length - 1;} else if (sectionIndex < 0) {sectionIndex = 0;}return sectionIndices[sectionIndex];}@Overridepublic int getSectionForPosition(int position) {for (int i = 0; i < sectionIndices.length; i++) {if (position < sectionIndices[i]) {return i - 1;}}return sectionIndices.length - 1;}class ViewHolder {ImageView ivComplete;TextView tvTitle;TextView tvCreateTime;}class HeaderViewHolder{TextView tvHeader;}
}

首先我们定义了下面两个数组,并且需要在构造的时候初始化它们:

[java] view plain copy print ?
  1. private int[] sectionIndices;
  2. private String[] sectionHeaders;
   private int[] sectionIndices;private String[] sectionHeaders;

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

但是我们要展现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 copy print ?
  1. public interface StickyListHeadersAdapter extends ListAdapter {
  2. View getHeaderView(int position, View convertView, ViewGroup parent);
  3. long getHeaderId(int position);
  4. }
public interface StickyListHeadersAdapter extends ListAdapter {View getHeaderView(int position, View convertView, ViewGroup parent);long getHeaderId(int position);
}

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

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

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

[java] view plain copy print ?
  1. public interface SectionIndexer {
  2. Object[] getSections();
  3. int getPositionForSection(int sectionIndex);
  4. int getSectionForPosition(int position);
  5. }
public interface SectionIndexer {Object[] getSections();int getPositionForSection(int sectionIndex);int getSectionForPosition(int position);
}

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

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

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

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

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

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

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

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

在xml中定义:

[html] view plain copy print ?
  1. <se.emilsjolander.stickylistheaders.StickyListHeadersListView
  2. android:id="@+id/lvTasks"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:background="@drawable/todo_bg"
  6. android:clipToPadding="false"
  7. android:divider="#44FFFFFF"
  8. android:dividerHeight="1dp"
  9. android:drawSelectorOnTop="true"
  10. android:fastScrollEnabled="true"
  11. android:overScrollMode="never"
  12. android:padding="16dp"
  13. android:scrollbarStyle="outsideOverlay" />
    <se.emilsjolander.stickylistheaders.StickyListHeadersListViewandroid:id="@+id/lvTasks"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/todo_bg"android:clipToPadding="false"android:divider="#44FFFFFF"android:dividerHeight="1dp"android:drawSelectorOnTop="true"android:fastScrollEnabled="true"android:overScrollMode="never"android:padding="16dp"android:scrollbarStyle="outsideOverlay" />

在MainActivity中使用:

[java] view plain copy print ?
  1. lvTasks = (StickyListHeadersListView) findViewById(R.id.lvTasks);
  2. taskAdapter = new StickListTaskAdapter(this, tasks);
  3. lvTasks.setAdapter(taskAdapter);
  4. lvTasks.setDrawingListUnderStickyHeader(true);
  5. lvTasks.setAreHeadersSticky(true);
  6. lvTasks.setOnItemLongClickListener(onItemLongClickListener);
  7. lvTasks.setOnItemClickListener(onItemClickListener);
     lvTasks = (StickyListHeadersListView) findViewById(R.id.lvTasks);taskAdapter = new StickListTaskAdapter(this, tasks);lvTasks.setAdapter(taskAdapter);lvTasks.setDrawingListUnderStickyHeader(true);lvTasks.setAreHeadersSticky(true);lvTasks.setOnItemLongClickListener(onItemLongClickListener);lvTasks.setOnItemClickListener(onItemClickListener);

而开源库中StickyListHeadersListView还提供了几个接口,可以让我们在Activity中去实现,不过这些就有待大家自己去慢慢学习了。

[java] view plain copy print ?
  1. public class StickyListHeadersListView extends FrameLayout {
  2. public interface OnHeaderClickListener {
  3. public void onHeaderClick(StickyListHeadersListView l, View header,
  4. int itemPosition, long headerId, boolean currentlySticky);
  5. }
  6. /**
  7. * Notifies the listener when the sticky headers top offset has changed.
  8. */
  9. public interface OnStickyHeaderOffsetChangedListener {
  10. /**
  11. * @param l      The view parent
  12. * @param header The currently sticky header being offset.
  13. *               This header is not guaranteed to have it's measurements set.
  14. *               It is however guaranteed that this view has been measured,
  15. *               therefor you should user getMeasured* methods instead of
  16. *               get* methods for determining the view's size.
  17. * @param offset The amount the sticky header is offset by towards to top of the screen.
  18. */
  19. public void onStickyHeaderOffsetChanged(StickyListHeadersListView l, View header, int offset);
  20. }
  21. /**
  22. * Notifies the listener when the sticky header has been updated
  23. */
  24. public interface OnStickyHeaderChangedListener {
  25. /**
  26. * @param l             The view parent
  27. * @param header        The new sticky header view.
  28. * @param itemPosition  The position of the item within the adapter's data set of
  29. *                      the item whose header is now sticky.
  30. * @param headerId      The id of the new sticky header.
  31. */
  32. public void onStickyHeaderChanged(StickyListHeadersListView l, View header,
  33. int itemPosition, long headerId);
  34. }
public class StickyListHeadersListView extends FrameLayout {public interface OnHeaderClickListener {public void onHeaderClick(StickyListHeadersListView l, View header,int itemPosition, long headerId, boolean currentlySticky);}/*** Notifies the listener when the sticky headers top offset has changed.*/public interface OnStickyHeaderOffsetChangedListener {/*** @param l      The view parent* @param header The currently sticky header being offset.*               This header is not guaranteed to have it's measurements set.*               It is however guaranteed that this view has been measured,*               therefor you should user getMeasured* methods instead of*               get* methods for determining the view's size.* @param offset The amount the sticky header is offset by towards to top of the screen.*/public void onStickyHeaderOffsetChanged(StickyListHeadersListView l, View header, int offset);}/*** Notifies the listener when the sticky header has been updated*/public interface OnStickyHeaderChangedListener {/*** @param l             The view parent* @param header        The new sticky header view.* @param itemPosition  The position of the item within the adapter's data set of*                      the item whose header is now sticky.* @param headerId      The id of the new sticky header.*/public void onStickyHeaderChanged(StickyListHeadersListView l, View header,int itemPosition, long headerId);}

结束。

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

ListView的分组实现相关推荐

  1. Xamarin使用ListView开启分组视图Cell数据展示bug处理

    问题描述 Xamarin使用IsGroupingEnabled="true"之后再Cell操作就会出现数据展示bug,数据不刷新的问题,如下图所示: 点击取消的是其他钢厂,但Vie ...

  2. Android学习小Demo(12)TodoList实现ListView的分组实现

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

  3. WPF,ListView设置分组

    CollectionViewSource 绑定的是从数据库取出的数据ListBind以DeptName为分组依据 <Window.Resources> <CollectionView ...

  4. android listview排序分组,Android:如何对ListView的数据进行排序?

    我有一些要从服务器中提取的JSON数据. 此数据中的字段之一是距离值. 我需要按照ListView中从最低到最高的距离对数据进行排序. 我不确定该怎么做? 任何帮助表示赞赏. 这是我获取数据的代码,不 ...

  5. android listview排序分组,Android:如何为ListView排序数据?

    我从服务器上下载了一些 JSON数据.该数据中的一个字段是距离值.我需要按ListView中从最低到最高的距离对数据进行排序.我不知道该怎么做呢? 任何帮助赞赏. 这是我的代码,以获取数据不确定如何正 ...

  6. android 分组 listview,Android实现的ListView分组布局改进示例

    本文实例讲述了android实现的listview分组布局改进方法.分享给大家供大家参考,具体如下: 由于是在网上转载的一篇文章,在这里就不多说废话了,首先看一下最终的效果图: 然后是实现该listv ...

  7. 强大的分组SectionListView, 支持自定义组头布局和分组的内容布局, 组头有挤压效果

    效果与系统的联系人分组效果类似,组头有挤压效果.但是不同的是,SectionListView支持每组的组头布局自定义,每组的内容布局也可以自定义. 效果图如下: 自定义Adapter: package ...

  8. java list套listview_ExpandableListView讲解(ListView的子类其作用类似于两个ListView的嵌套)...

    /* * 记录一下方便查阅 */ 有时候,使用ListView并不能满足应用程序所需要的功能.有些应用程序需要多组ListView,这时候我们就要使用一种新的控件ExpandableListView- ...

  9. ReactNative进阶(四十一):应用 FlatList 实现分组列表

    一.功能简介 二.属性说明 三.方法集合 四.简单应用示例 五.高阶应用示例 六.拓展阅读 一.功能简介 FlatList为高性能的简单列表组件,支持下面这些常用的功能: 完全跨平台. 支持水平布局模 ...

最新文章

  1. Windows下Mex程序的调试
  2. 被围绕的区域(dfs)
  3. linux进程调度周期,Linux进程组调度机制学习
  4. Winform(C#)输入完毕后,按Enter键触发Button事件
  5. windows驱动开发学习
  6. Tips--Altium Designer 安装时出现Account log in
  7. oracle 11g的启动和关闭
  8. 各个系统下关闭占用端口号的进程
  9. 【bzoj4443】[Scoi2015]小凸玩矩阵 二分+二分图最大匹配
  10. ListView中有Checkbox时的点击和选择问题
  11. 七种场景下的软件作业量估计
  12. 全球与中国SS-OCT激光市场深度研究分析报告
  13. 用frp开源工具,实现内网穿透(详细教程)
  14. css 三角角标样式
  15. ip地址的作用及分类
  16. 存储卡种类及其应用大盘点
  17. 熊猫烧香作者李俊的个人简历
  18. 抽象类之定义一个Point类,最后重新定义Rectangle类,使其同时继承Shape和Point类(Point视作Rectangle的左上角),并在Rectangle中添加一些新的成员。
  19. 腾讯云GPU桌面服务器驱动安装
  20. 诺基亚java游戏那种_非诺基亚手机如何玩S40 Java游戏_网易手机频道

热门文章

  1. 善行天下,大爱无疆 ——云创再次获赠爱心锦旗!
  2. python 二维列表(数组)赋值问题
  3. C++的MFC,与C#的.NET
  4. mysql怎么用sequence_mysql实现sequence功能的代码
  5. 《博客园精华集--WEB分册》第三轮结果--心痛时刻一如既往
  6. 头歌-信息安全技术-安全审计
  7. 访问控制列表--扩展ACL、命名的ACL
  8. 轻轻回首,重重抬眸,只做自己——2021,QGIS课堂和你在一起
  9. ubuntu 永久打开USB串口权限、232串口权限
  10. m4r格式转换器 怎么把MP3格式转为m4r格式