SectionedRecyclerViewAdapter.java 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /**
  2. * Copyright 2016 Aidan Follestad
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an
  12. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
  13. * either express or implied. See the License for the specific language
  14. * governing permissions and limitations under the License.
  15. */
  16. package com.afollestad.sectionedrecyclerview;
  17. import android.support.annotation.IntRange;
  18. import android.support.annotation.Nullable;
  19. import android.support.v4.util.ArrayMap;
  20. import android.support.v7.widget.GridLayoutManager;
  21. import android.support.v7.widget.RecyclerView;
  22. import android.support.v7.widget.StaggeredGridLayoutManager;
  23. import android.view.ViewGroup;
  24. import java.util.List;
  25. /**
  26. * @author Aidan Follestad (afollestad)
  27. */
  28. public abstract class SectionedRecyclerViewAdapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {
  29. protected final static int VIEW_TYPE_HEADER = -2;
  30. protected final static int VIEW_TYPE_ITEM = -1;
  31. private final ArrayMap<Integer, Integer> mHeaderLocationMap;
  32. private GridLayoutManager mLayoutManager;
  33. private ArrayMap<Integer, Integer> mSpanMap;
  34. private boolean mShowHeadersForEmptySections;
  35. public SectionedRecyclerViewAdapter() {
  36. mHeaderLocationMap = new ArrayMap<>();
  37. }
  38. public abstract int getSectionCount();
  39. public abstract int getItemCount(int section);
  40. public abstract void onBindHeaderViewHolder(VH holder, int section);
  41. public abstract void onBindViewHolder(VH holder, int section, int relativePosition, int absolutePosition);
  42. public final boolean isHeader(int position) {
  43. return mHeaderLocationMap.get(position) != null;
  44. }
  45. /**
  46. * Instructs the list view adapter to whether show headers for empty sections or not.
  47. *
  48. * @param show flag indicating whether headers for empty sections ought to be shown.
  49. */
  50. public final void shouldShowHeadersForEmptySections(boolean show) {
  51. mShowHeadersForEmptySections = show;
  52. }
  53. public final void setLayoutManager(@Nullable GridLayoutManager lm) {
  54. mLayoutManager = lm;
  55. if (lm == null) return;
  56. lm.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
  57. @Override
  58. public int getSpanSize(int position) {
  59. if (isHeader(position))
  60. return mLayoutManager.getSpanCount();
  61. final int[] sectionAndPos = getSectionIndexAndRelativePosition(position);
  62. final int absPos = position - (sectionAndPos[0] + 1);
  63. return getRowSpan(mLayoutManager.getSpanCount(),
  64. sectionAndPos[0], sectionAndPos[1], absPos);
  65. }
  66. });
  67. }
  68. @SuppressWarnings("UnusedParameters")
  69. protected int getRowSpan(int fullSpanSize, int section, int relativePosition, int absolutePosition) {
  70. return 1;
  71. }
  72. // returns section along with offsetted position
  73. private int[] getSectionIndexAndRelativePosition(int itemPosition) {
  74. synchronized (mHeaderLocationMap) {
  75. Integer lastSectionIndex = -1;
  76. for (final Integer sectionIndex : mHeaderLocationMap.keySet()) {
  77. if (itemPosition > sectionIndex) {
  78. lastSectionIndex = sectionIndex;
  79. } else {
  80. break;
  81. }
  82. }
  83. return new int[]{mHeaderLocationMap.get(lastSectionIndex), itemPosition - lastSectionIndex - 1};
  84. }
  85. }
  86. @Override
  87. public final int getItemCount() {
  88. int count = 0;
  89. mHeaderLocationMap.clear();
  90. for (int s = 0; s < getSectionCount(); s++) {
  91. int itemCount = getItemCount(s);
  92. if (mShowHeadersForEmptySections || (itemCount > 0)) {
  93. mHeaderLocationMap.put(count, s);
  94. count += itemCount + 1;
  95. }
  96. }
  97. return count;
  98. }
  99. /**
  100. * @hide
  101. * @deprecated
  102. */
  103. @Override
  104. @Deprecated
  105. public final int getItemViewType(int position) {
  106. if (isHeader(position)) {
  107. return getHeaderViewType(mHeaderLocationMap.get(position));
  108. } else {
  109. final int[] sectionAndPos = getSectionIndexAndRelativePosition(position);
  110. return getItemViewType(sectionAndPos[0],
  111. // offset section view positions
  112. sectionAndPos[1],
  113. position - (sectionAndPos[0] + 1));
  114. }
  115. }
  116. @SuppressWarnings("UnusedParameters")
  117. @IntRange(from = 0, to = Integer.MAX_VALUE)
  118. public int getHeaderViewType(int section) {
  119. //noinspection ResourceType
  120. return VIEW_TYPE_HEADER;
  121. }
  122. @SuppressWarnings("UnusedParameters")
  123. @IntRange(from = 0, to = Integer.MAX_VALUE)
  124. public int getItemViewType(int section, int relativePosition, int absolutePosition) {
  125. //noinspection ResourceType
  126. return VIEW_TYPE_ITEM;
  127. }
  128. /**
  129. * @hide
  130. * @deprecated
  131. */
  132. @Override
  133. @Deprecated
  134. public final void onBindViewHolder(VH holder, int position) {
  135. StaggeredGridLayoutManager.LayoutParams layoutParams = null;
  136. if (holder.itemView.getLayoutParams() instanceof GridLayoutManager.LayoutParams)
  137. layoutParams = new StaggeredGridLayoutManager.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
  138. else if (holder.itemView.getLayoutParams() instanceof StaggeredGridLayoutManager.LayoutParams)
  139. layoutParams = (StaggeredGridLayoutManager.LayoutParams) holder.itemView.getLayoutParams();
  140. if (isHeader(position)) {
  141. if (layoutParams != null) layoutParams.setFullSpan(true);
  142. onBindHeaderViewHolder(holder, mHeaderLocationMap.get(position));
  143. } else {
  144. if (layoutParams != null) layoutParams.setFullSpan(false);
  145. final int[] sectionAndPos = getSectionIndexAndRelativePosition(position);
  146. final int absPos = position - (sectionAndPos[0] + 1);
  147. onBindViewHolder(holder, sectionAndPos[0],
  148. // offset section view positions
  149. sectionAndPos[1], absPos);
  150. }
  151. if (layoutParams != null)
  152. holder.itemView.setLayoutParams(layoutParams);
  153. }
  154. /**
  155. * @hide
  156. * @deprecated
  157. */
  158. @Deprecated
  159. @Override
  160. public final void onBindViewHolder(VH holder, int position, List<Object> payloads) {
  161. super.onBindViewHolder(holder, position, payloads);
  162. }
  163. }