1+ package com .timehop .stickyheadersrecyclerview .decorators ;
2+
3+ import android .content .Context ;
4+ import android .graphics .Rect ;
5+ import android .support .annotation .DimenRes ;
6+ import android .support .v7 .widget .GridLayoutManager ;
7+ import android .support .v7 .widget .LinearLayoutManager ;
8+ import android .support .v7 .widget .OrientationHelper ;
9+ import android .support .v7 .widget .RecyclerView ;
10+ import android .support .v7 .widget .StaggeredGridLayoutManager ;
11+ import android .view .View ;
12+
13+ /**
14+ * Created by Rafael Baboni Dominiquini on 30/06/16.
15+ */
16+ public class RecyclerSpacingDecoration extends RecyclerView .ItemDecoration {
17+
18+ private int orientation = -1 ;
19+ private int spanCount = -1 ;
20+
21+ private int fullSpacing ;
22+ private int halfSpacing ;
23+
24+ public RecyclerSpacingDecoration (Context context , @ DimenRes int spacingDimen ) {
25+
26+ this (context .getResources ().getDimensionPixelSize (spacingDimen ));
27+ }
28+
29+ public RecyclerSpacingDecoration (int spacingPx ) {
30+
31+ fullSpacing = spacingPx ;
32+ halfSpacing = spacingPx / 2 ;
33+ }
34+
35+ @ Override
36+ public void getItemOffsets (Rect outRect , View view , RecyclerView parent , RecyclerView .State state ) {
37+
38+ super .getItemOffsets (outRect , view , parent , state );
39+
40+ if (orientation == -1 ) {
41+ orientation = getOrientation (parent );
42+ }
43+
44+ if (spanCount == -1 ) {
45+ spanCount = getTotalSpan (parent );
46+ }
47+
48+ int childCount = parent .getLayoutManager ().getItemCount ();
49+ int childIndex = parent .getChildAdapterPosition (view );
50+
51+ int itemSpanSize = getItemSpanSize (parent , childIndex );
52+ int spanIndex = getItemSpanIndex (parent , childIndex );
53+
54+ if (spanCount > 0 ) {
55+ setSpacings (outRect , parent , childCount , childIndex , itemSpanSize , spanIndex );
56+ }
57+ }
58+
59+ protected void setSpacings (Rect outRect , RecyclerView parent , int childCount , int childIndex , int itemSpanSize , int spanIndex ) {
60+
61+ outRect .top = 0 ;
62+ outRect .bottom = fullSpacing ;
63+ outRect .left = halfSpacing ;
64+ outRect .right = halfSpacing ;
65+
66+ if (isTopEdge (parent , childCount , childIndex , itemSpanSize , spanIndex )) {
67+ outRect .top = fullSpacing ;
68+ }
69+
70+ if (isLeftEdge (parent , childCount , childIndex , itemSpanSize , spanIndex )) {
71+ outRect .left = fullSpacing ;
72+ }
73+
74+ if (isRightEdge (parent , childCount , childIndex , itemSpanSize , spanIndex )) {
75+ outRect .right = fullSpacing ;
76+ }
77+
78+ if (isBottomEdge (parent , childCount , childIndex , itemSpanSize , spanIndex )) {
79+ outRect .bottom = fullSpacing ;
80+ }
81+ }
82+
83+ protected int getTotalSpan (RecyclerView parent ) {
84+
85+ RecyclerView .LayoutManager mgr = parent .getLayoutManager ();
86+ if (mgr instanceof GridLayoutManager ) {
87+ return ((GridLayoutManager ) mgr ).getSpanCount ();
88+ } else if (mgr instanceof StaggeredGridLayoutManager ) {
89+ return ((StaggeredGridLayoutManager ) mgr ).getSpanCount ();
90+ } else if (mgr instanceof LinearLayoutManager ) {
91+ return 1 ;
92+ }
93+
94+ return -1 ;
95+ }
96+
97+ protected int getItemSpanSize (RecyclerView parent , int childIndex ) {
98+
99+ RecyclerView .LayoutManager mgr = parent .getLayoutManager ();
100+ if (mgr instanceof GridLayoutManager ) {
101+ return ((GridLayoutManager ) mgr ).getSpanSizeLookup ().getSpanSize (childIndex );
102+ } else if (mgr instanceof StaggeredGridLayoutManager ) {
103+ return 1 ;
104+ } else if (mgr instanceof LinearLayoutManager ) {
105+ return 1 ;
106+ }
107+
108+ return -1 ;
109+ }
110+
111+ protected int getItemSpanIndex (RecyclerView parent , int childIndex ) {
112+
113+ RecyclerView .LayoutManager mgr = parent .getLayoutManager ();
114+ if (mgr instanceof GridLayoutManager ) {
115+ return ((GridLayoutManager ) mgr ).getSpanSizeLookup ().getSpanIndex (childIndex , spanCount );
116+ } else if (mgr instanceof StaggeredGridLayoutManager ) {
117+ return childIndex % spanCount ;
118+ } else if (mgr instanceof LinearLayoutManager ) {
119+ return 0 ;
120+ }
121+
122+ return -1 ;
123+ }
124+
125+ protected int getOrientation (RecyclerView parent ) {
126+
127+ RecyclerView .LayoutManager mgr = parent .getLayoutManager ();
128+ if (mgr instanceof LinearLayoutManager ) {
129+ return ((LinearLayoutManager ) mgr ).getOrientation ();
130+ } else if (mgr instanceof GridLayoutManager ) {
131+ return ((GridLayoutManager ) mgr ).getOrientation ();
132+ } else if (mgr instanceof StaggeredGridLayoutManager ) {
133+ return ((StaggeredGridLayoutManager ) mgr ).getOrientation ();
134+ }
135+
136+ return OrientationHelper .VERTICAL ;
137+ }
138+
139+ protected boolean isLeftEdge (RecyclerView parent , int childCount , int childIndex , int itemSpanSize , int spanIndex ) {
140+
141+ if (orientation == OrientationHelper .VERTICAL ) {
142+ return spanIndex == 0 ;
143+ } else {
144+ return (childIndex == 0 ) || isFirstItemEdgeValid ((childIndex < spanCount ), parent , childIndex );
145+ }
146+ }
147+
148+ protected boolean isRightEdge (RecyclerView parent , int childCount , int childIndex , int itemSpanSize , int spanIndex ) {
149+
150+ if (orientation == OrientationHelper .VERTICAL ) {
151+ return (spanIndex + itemSpanSize ) == spanCount ;
152+ } else {
153+ return isLastItemEdgeValid ((childIndex >= childCount - spanCount ), parent , childCount , childIndex , spanIndex );
154+ }
155+ }
156+
157+ protected boolean isTopEdge (RecyclerView parent , int childCount , int childIndex , int itemSpanSize , int spanIndex ) {
158+
159+ if (orientation == OrientationHelper .VERTICAL ) {
160+ return (childIndex == 0 ) || isFirstItemEdgeValid ((childIndex < spanCount ), parent , childIndex );
161+ } else {
162+ return spanIndex == 0 ;
163+ }
164+ }
165+
166+ protected boolean isBottomEdge (RecyclerView parent , int childCount , int childIndex , int itemSpanSize , int spanIndex ) {
167+
168+ if (orientation == OrientationHelper .VERTICAL ) {
169+ return isLastItemEdgeValid ((childIndex >= childCount - spanCount ), parent , childCount , childIndex , spanIndex );
170+ } else {
171+ return (spanIndex + itemSpanSize ) == spanCount ;
172+ }
173+ }
174+
175+ protected boolean isFirstItemEdgeValid (boolean isOneOfFirstItems , RecyclerView parent , int childIndex ) {
176+
177+ int totalSpanArea = 0 ;
178+
179+ if (isOneOfFirstItems ) {
180+ for (int i = childIndex ; i >= 0 ; i --) {
181+ totalSpanArea = totalSpanArea + getItemSpanSize (parent , i );
182+ }
183+ }
184+
185+ return isOneOfFirstItems && totalSpanArea <= spanCount ;
186+ }
187+
188+ protected boolean isLastItemEdgeValid (boolean isOneOfLastItems , RecyclerView parent , int childCount , int childIndex , int spanIndex ) {
189+
190+ int totalSpanRemaining = 0 ;
191+
192+ if (isOneOfLastItems ) {
193+ for (int i = childIndex ; i < childCount ; i ++) {
194+ totalSpanRemaining = totalSpanRemaining + getItemSpanSize (parent , i );
195+ }
196+ }
197+
198+ return isOneOfLastItems && (totalSpanRemaining <= spanCount - spanIndex );
199+ }
200+ }
0 commit comments