12 | * 分组adapter,支持多种group布局,多种child布局
13 | */
14 |
15 | public abstract class NestedAdapter
14 | * 分隔条。支持为 {@link NestedAdapter}添加头部,尾部,group间,child间,group和child间添加自定义divider
15 | *
16 | * @see NestedAdapterDivider#setDividerBeforeFirstGroup(Drawable)
17 | * @see NestedAdapterDivider#setDividerAfterLastGroup(Drawable)
18 | * @see NestedAdapterDivider#setDividerBetweenChild(Drawable)
19 | * @see NestedAdapterDivider#setDividerBetweenGroupAndChild(Drawable)
20 | * @see NestedAdapterDivider#setDividerBetweenGroup(Drawable)
21 | */
22 |
23 | public class NestedAdapterDivider extends DividerItemDecoration {
24 |
25 | protected final int orientation;
26 | private final Rect mBounds = new Rect();
27 | private Drawable dividerBetweenGroup;
28 | private Drawable dividerBetweenChild;
29 | private Drawable dividerBetweenGroupAndChild;
30 | private Drawable dividerBeforeFirstGroup;
31 | private Drawable dividerAfterLastGroup;
32 |
33 | public NestedAdapterDivider(Context context, int orientation) {
34 | super(context, orientation);
35 | this.orientation = orientation;
36 | }
37 |
38 |
39 | @Override
40 | public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
41 | if (isNeedIntercept(parent) == false) {
42 | super.onDraw(c, parent, state);
43 | return;
44 | }
45 |
46 | if (parent.getLayoutManager() == null) {
47 | return;
48 | }
49 | NestedAdapter adapter = (NestedAdapter) parent.getAdapter();
50 | if (orientation == VERTICAL) {
51 | drawVertical(c, parent, adapter);
52 | } else {
53 | drawHorizontal(c, parent, adapter);
54 | }
55 | }
56 |
57 |
58 | private void drawVertical(Canvas canvas, RecyclerView parent, NestedAdapter adapter) {
59 | canvas.save();
60 | final int left;
61 | final int right;
62 | //noinspection AndroidLintNewApi - NewApi lint fails to handle overrides.
63 | if (parent.getClipToPadding()) {
64 | left = parent.getPaddingLeft();
65 | right = parent.getWidth() - parent.getPaddingRight();
66 | canvas.clipRect(left, parent.getPaddingTop(), right,
67 | parent.getHeight() - parent.getPaddingBottom());
68 | } else {
69 | left = 0;
70 | right = parent.getWidth();
71 | }
72 |
73 | final int childCount = parent.getChildCount();
74 | for (int i = 0; i < childCount; i++) {
75 | final View child = parent.getChildAt(i);
76 | getDecoratedBoundsWithMarginsInt(child, mBounds);
77 | mBounds.bottom -= child.getHeight();
78 |
79 | int position = ((RecyclerView.LayoutParams) child.getLayoutParams()).getViewAdapterPosition();
80 | final int bottom = mBounds.bottom + Math.round(child.getTranslationY());
81 | Drawable divider = getDrawableForChild(position, adapter);
82 | if (divider != null) {
83 | final int top = bottom - divider.getIntrinsicHeight();
84 | divider.setBounds(left, top, right, bottom);
85 | divider.draw(canvas);
86 | }
87 | }
88 | if (childCount > 0 && dividerAfterLastGroup != null) {
89 | View child = parent.getChildAt(childCount - 1);
90 | int position = ((RecyclerView.LayoutParams) child.getLayoutParams()).getViewAdapterPosition();
91 | if (position == adapter.getItemCount() - 1) {
92 | getDecoratedBoundsWithMarginsInt(child, mBounds);
93 |
94 | final int top = mBounds.bottom + Math.round(child.getTranslationY());
95 | Drawable divider = dividerAfterLastGroup;
96 | final int bottom = top + divider.getIntrinsicHeight();
97 | divider.setBounds(left, top, right, bottom);
98 | divider.draw(canvas);
99 | }
100 | }
101 |
102 | canvas.restore();
103 | }
104 |
105 | private void getDecoratedBoundsWithMarginsInt(View view, Rect outBounds) {
106 | final RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) view.getLayoutParams();
107 | outBounds.set(view.getLeft() - lp.leftMargin,
108 | view.getTop() - lp.topMargin,
109 | view.getRight() + lp.rightMargin,
110 | view.getBottom() + lp.bottomMargin);
111 | }
112 |
113 | private void drawHorizontal(Canvas canvas, RecyclerView parent, NestedAdapter adapter) {
114 | canvas.save();
115 | final int top;
116 | final int bottom;
117 | //noinspection AndroidLintNewApi - NewApi lint fails to handle overrides.
118 | if (parent.getClipToPadding()) {
119 | top = parent.getPaddingTop();
120 | bottom = parent.getHeight() - parent.getPaddingBottom();
121 | canvas.clipRect(parent.getPaddingLeft(), top,
122 | parent.getWidth() - parent.getPaddingRight(), bottom);
123 | } else {
124 | top = 0;
125 | bottom = parent.getHeight();
126 | }
127 |
128 | final int childCount = parent.getChildCount();
129 | for (int i = 0; i < childCount; i++) {
130 | final View child = parent.getChildAt(i);
131 | getDecoratedBoundsWithMarginsInt(child, mBounds);
132 | mBounds.right -= child.getWidth();
133 | int position = ((RecyclerView.LayoutParams) child.getLayoutParams()).getViewAdapterPosition();
134 |
135 | final int right = mBounds.right + Math.round(child.getTranslationX());
136 | Drawable divider = getDrawableForChild(position, adapter);
137 | if (divider != null) {
138 | final int left = right - divider.getIntrinsicWidth();
139 | divider.setBounds(left, top, right, bottom);
140 | divider.draw(canvas);
141 | }
142 | }
143 |
144 | if (childCount > 0 && dividerAfterLastGroup != null) {
145 | View child = parent.getChildAt(childCount - 1);
146 | int position = ((RecyclerView.LayoutParams) child.getLayoutParams()).getViewAdapterPosition();
147 | if (position == adapter.getItemCount() - 1) {
148 | getDecoratedBoundsWithMarginsInt(child, mBounds);
149 | final int left = mBounds.right + Math.round(child.getTranslationX());
150 | Drawable divider = dividerAfterLastGroup;
151 | final int right = left + divider.getIntrinsicWidth();
152 | divider.setBounds(left, top, right, bottom);
153 | divider.draw(canvas);
154 | }
155 | }
156 |
157 | canvas.restore();
158 | }
159 |
160 |
161 | @Override
162 | public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
163 | if (isNeedIntercept(parent) == false) {
164 | super.getItemOffsets(outRect, view, parent, state);
165 | return;
166 | }
167 | NestedAdapter adapter = ((NestedAdapter) parent.getAdapter());
168 | int position = ((RecyclerView.LayoutParams) view.getLayoutParams()).getViewAdapterPosition();
169 |
170 | int lastPosition = adapter.getItemCount() - 1;
171 | if (position == 0) {
172 | int l = 0, t = 0, r = 0, b = 0;
173 | if (dividerBeforeFirstGroup != null) {
174 | if (orientation == VERTICAL) {
175 | t = dividerBeforeFirstGroup.getIntrinsicHeight();
176 | } else {
177 | l = dividerBeforeFirstGroup.getIntrinsicWidth();
178 | }
179 | }
180 | setRightBottom(outRect, position, lastPosition, l, t, r, b);
181 | return;
182 | }
183 |
184 | int groupCount = adapter.getSafeGroupCount();
185 | int count = 0;
186 | for (int i = 0; i < groupCount; i++) {
187 | int l = 0, t = 0, r = 0, b = 0;
188 | if (count == position) {
189 | if (dividerBetweenGroup != null) {
190 | if (orientation == VERTICAL) {
191 | t = dividerBetweenGroup.getIntrinsicHeight();
192 | } else {
193 | l = dividerBetweenGroup.getIntrinsicWidth();
194 | }
195 | }
196 | setRightBottom(outRect, position, lastPosition, l, t, r, b);
197 | return;
198 | }
199 | count++;
200 |
201 | int childCount = adapter.getSafeChildCount(i);
202 |
203 | if (count + childCount > position) {
204 | int childIndex = position - count;
205 |
206 | if (childIndex == 0) {
207 | if (dividerBetweenGroupAndChild != null) {
208 | if (orientation == VERTICAL) {
209 | t = dividerBetweenGroupAndChild.getIntrinsicHeight();
210 | } else {
211 | l = dividerBetweenGroupAndChild.getIntrinsicWidth();
212 | }
213 | }
214 |
215 | setRightBottom(outRect, position, lastPosition, l, t, r, b);
216 | return;
217 | } else {
218 | if (dividerBetweenChild != null) {
219 | if (orientation == VERTICAL) {
220 | t = dividerBetweenChild.getIntrinsicHeight();
221 | } else {
222 | l = dividerBetweenChild.getIntrinsicWidth();
223 | }
224 |
225 | }
226 | setRightBottom(outRect, position, lastPosition, l, t, r, b);
227 | return;
228 | }
229 |
230 | }
231 | count += childCount;
232 | }
233 |
234 |
235 | }
236 |
237 | private void setRightBottom(Rect outRect, int position, int lastPosition, int l, int t, int r, int b) {
238 | if (position == lastPosition) {
239 | if (dividerAfterLastGroup != null) {
240 | if (orientation == VERTICAL) {
241 | b = dividerAfterLastGroup.getIntrinsicHeight();
242 | } else {
243 | r = dividerAfterLastGroup.getIntrinsicWidth();
244 | }
245 | }
246 | }
247 | outRect.set(l, t, r, b);
248 | }
249 |
250 | private Drawable getDrawableForChild(int position, NestedAdapter adapter) {
251 | if (position == 0) {
252 | return dividerBeforeFirstGroup;
253 | }
254 | int groupCount = adapter.getSafeGroupCount();
255 | int count = 0;
256 | for (int i = 0; i < groupCount; i++) {
257 | if (count == position) {
258 | return dividerBetweenGroup;
259 | }
260 | count++;
261 |
262 | int childCount = adapter.getSafeChildCount(i);
263 |
264 | if (count + childCount > position) {
265 | int childIndex = position - count;
266 |
267 | if (childIndex == 0) {
268 | return dividerBetweenGroupAndChild;
269 | } else {
270 | return dividerBetweenChild;
271 | }
272 |
273 | }
274 | count += childCount;
275 | }
276 |
277 | return null;
278 | }
279 |
280 | public NestedAdapterDivider setDividerBetweenGroup(Drawable dividerBetweenGroup) {
281 | this.dividerBetweenGroup = dividerBetweenGroup;
282 | return this;
283 | }
284 |
285 | public NestedAdapterDivider setDividerBetweenChild(Drawable dividerBetweenChild) {
286 | this.dividerBetweenChild = dividerBetweenChild;
287 | return this;
288 | }
289 |
290 | public NestedAdapterDivider setDividerBetweenGroupAndChild(Drawable dividerBetweenGroupAndChild) {
291 | this.dividerBetweenGroupAndChild = dividerBetweenGroupAndChild;
292 | return this;
293 | }
294 |
295 | public NestedAdapterDivider setDividerBeforeFirstGroup(Drawable dividerBeforeFirstGroup) {
296 | this.dividerBeforeFirstGroup = dividerBeforeFirstGroup;
297 | return this;
298 | }
299 |
300 | public NestedAdapterDivider setDividerAfterLastGroup(Drawable dividerAfterLastGroup) {
301 | this.dividerAfterLastGroup = dividerAfterLastGroup;
302 | return this;
303 | }
304 |
305 |
306 | private boolean isNeedIntercept(RecyclerView recyclerView) {
307 | if (recyclerView == null) {
308 | return false;
309 | }
310 | return recyclerView.getAdapter() instanceof NestedAdapter;
311 | }
312 |
313 | }
314 |
--------------------------------------------------------------------------------
/lib/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |