17 | * You can use it like {@link android.support.v7.widget.LinearLayoutManager}.Just execute
18 | * {@link android.support.v7.widget.RecyclerView#setLayoutManager(RecyclerView.LayoutManager)}
19 | * with param.You must set one of the {@link Orientation} when you instance a HiveLayoutManager
20 | * and it don't support change after construct at present.
21 | */
22 | public class HiveLayoutManager extends RecyclerView.LayoutManager {
23 |
24 |
25 | private static final String TAG = HiveLayoutManager.class.getSimpleName();
26 |
27 | /**
28 | * layout views in RV an horizontal direction
29 | */
30 | public static final int HORIZONTAL = HiveLayoutHelper.HORIZONTAL;
31 |
32 | /**
33 | * layout views in RV an vertical direction
34 | */
35 | public static final int VERTICAL = HiveLayoutHelper.VERTICAL;
36 |
37 | /**
38 | * at the center of parent at begin
39 | */
40 | public static final int CENTER = 0x00000001;
41 |
42 | /**
43 | * at the left of parent at begin
44 | */
45 | public static final int ALIGN_LEFT = 0x00000002;
46 |
47 | /**
48 | * at the right of parent at begin, if already set ALIGN_LEFT, this will not work
49 | */
50 | public static final int ALIGN_RIGHT = 0x00000004;
51 |
52 | /**
53 | * at the top of parent at begin
54 | */
55 | public static final int ALIGN_TOP = 0x00000008;
56 |
57 | /**
58 | * at the bottom of parent at begin, if already set ALIGN_TOP, this will not work
59 | */
60 | public static final int ALIGN_BOTTOM = 0x00000010;
61 |
62 | /**
63 | * the HiveLayoutManager's orientation
64 | *
65 | * @see #VERTICAL
66 | * @see #HORIZONTAL
67 | */
68 | @IntDef({HORIZONTAL, VERTICAL})
69 | @interface Orientation {
70 | }
71 |
72 | private IHiveMathUtils mHiveMathUtils;
73 | private AnchorInfo mAnchorInfo;
74 | private LayoutState mLayoutState;
75 | private final List
113 | * you can use them combined, like setGravity(ALIGN_LEFT | ALIGN_TOP) will let the layoutManager
114 | * at the left top of the parent at begin.
115 | */
116 | public void setGravity(final int gravity) {
117 | this.mGravity = gravity;
118 | }
119 |
120 | /**
121 | * set the layout manager padding.if you need recyclerView have a padding,you can use this to
122 | * solve the problem that item cannot disappear from the edge of view.
123 | *
124 | * @param paddingLeft
125 | * @param paddingTop
126 | * @param paddingRight
127 | * @param paddingBottom
128 | */
129 | public void setPadding(float paddingLeft, float paddingTop, float paddingRight, float paddingBottom) {
130 | mPadding.set(paddingLeft, paddingTop, paddingRight, paddingBottom);
131 | }
132 |
133 |
134 | @Override
135 | public RecyclerView.LayoutParams generateDefaultLayoutParams() {
136 | return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
137 | ViewGroup.LayoutParams.WRAP_CONTENT);
138 | }
139 |
140 | @Override
141 | public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
142 |
143 | detachAndScrapAttachedViews(recycler);
144 | int itemCount = state.getItemCount();
145 | if (itemCount <= 0) {
146 | return;
147 | }
148 | initAnchorInfo(recycler);
149 | initFloors();
150 | initEdgeDistance();
151 | detachAndScrapAttachedViews(recycler);
152 |
153 | mBooleanMap.reset();
154 |
155 | fill(recycler, state);
156 | firstLayout = false;
157 | }
158 |
159 | private void initEdgeDistance() {
160 | mLayoutState.edgeDistance.set(getWidth() / 2, getHeight() / 2, getWidth() / 2, getHeight() / 2);
161 | }
162 |
163 | private void updateLayoutState() {
164 | mLayoutState.containerRect.set(0, 0, getWidth(), getHeight());
165 | mLayoutState.containerRect.offset(-mLayoutState.offsetX, -mLayoutState.offsetY);
166 | }
167 |
168 | private void fill(RecyclerView.Recycler recycler, RecyclerView.State state) {
169 | int itemCount = state.getItemCount();
170 | if (itemCount <= 0) {
171 | return;
172 | }
173 |
174 | checkAllRect(itemCount);
175 | updateLayoutState();
176 |
177 | if (firstLayout) {
178 | firstLayout = false;
179 | if ((mGravity & CENTER) == 0) { // 不是Center的时候
180 | if ((mGravity & ALIGN_LEFT) != 0) { // 如果是从左对其
181 | doScrollHorizontalBx(recycler, state, mLayoutState.outLineRect.left - mPadding.left);
182 | } else if ((mGravity & ALIGN_RIGHT) != 0) {
183 | doScrollHorizontalBx(recycler, state, mLayoutState.outLineRect.right - getWidth() + mPadding.right);
184 | }
185 | if ((mGravity & ALIGN_TOP) != 0) {
186 | doScrollVerticalBy(recycler, state, mLayoutState.outLineRect.top - mPadding.top);
187 | } else if ((mGravity & ALIGN_BOTTOM) != 0) {
188 | doScrollVerticalBy(recycler, state, mLayoutState.outLineRect.bottom - getHeight() + mPadding.bottom);
189 | }
190 | } else {
191 | fill(recycler, state);
192 | }
193 | } else {
194 | for (int i = 0; i < itemCount; i++) {
195 | RectF bounds = getBounds(i);
196 |
197 | if (!mBooleanMap.get(i) && RectF.intersects(bounds, mLayoutState.containerRect)) {
198 | View view = recycler.getViewForPosition(i);
199 | addView(view);
200 | mBooleanMap.set(i);
201 | measureChildWithMargins(view, 0, 0);
202 |
203 | bounds.offset(mLayoutState.offsetX, mLayoutState.offsetY);
204 |
205 | calculateEdgeDistance(bounds.left, bounds.top, bounds.right, bounds.bottom);
206 |
207 | layoutDecoratedWithMargins(view, (int) bounds.left, (int) bounds.top, (int) bounds.right, (int) bounds.bottom);
208 | }
209 | }
210 | }
211 |
212 | }
213 |
214 | private void calculateEdgeDistance(float left, float top, float right, float bottom) {
215 | RectF temp = mLayoutState.edgeDistance;
216 | float eLeft = Math.min(temp.left, left);
217 | float eTop = Math.min(temp.top, top);
218 | float eRight = Math.min(temp.right, getWidth() - right);
219 | float eBottom = Math.min(temp.bottom, getHeight() - bottom);
220 | mLayoutState.edgeDistance.set(eLeft, eTop, eRight, eBottom);
221 | }
222 |
223 | private RectF getBounds(int index) {
224 | HivePositionInfo positionInfo = mHiveMathUtils.getFloorOfPosition(index);
225 | List
14 | * this interface include many method for calculate the mPosition of view in RV.
15 | */
16 | interface IHiveMathUtils {
17 |
18 | /**
19 | * calculate a item's bounds that beside of current item .
20 | *
21 | * @param current current item bounds
22 | * @param number the public edge number
23 | * @param length the length of regular hexagon
24 | * @return the item bounds
25 | */
26 | RectF calculateItemBounds(@NonNull RectF current, int number, float length);
27 |
28 | /**
29 | * calculate a item's center point that beside of current item .
30 | *
31 | * @param current current item center point
32 | * @param number the public edge number
33 | * @param length the length of regular hexagon
34 | * @return the center point
35 | */
36 | PointF calculateCenterPoint(@NonNull PointF current, int number, float length);
37 |
38 | /**
39 | * get the distance of neighbour item' center point.
40 | *
41 | * @param length the length of regular hexagon
42 | * @return the distance of neighbour item' center point
43 | */
44 | double getDistanceOfNeighbourCenter(float length);
45 |
46 | /**
47 | * clone a PointF object from current
48 | *
49 | * @param pointF resource
50 | * @return
51 | */
52 | PointF clone(@NonNull PointF pointF);
53 |
54 | /**
55 | * get {@link jack.hive.HiveConstants.VerticalNumber} from the edge number
56 | *
57 | * @param i edge number
58 | * @return the {@link jack.hive.HiveConstants.VerticalNumber}
59 | */
60 | @HiveConstants.VerticalNumber
61 | int getVerticalNumber(int i);
62 |
63 | /**
64 | * get {@link jack.hive.HiveConstants.HorizontalNumber} from the edge number
65 | *
66 | * @param i edge number
67 | * @return the {@link jack.hive.HiveConstants.HorizontalNumber}
68 | */
69 | @HiveConstants.HorizontalNumber
70 | int getHorizontalNumber(int i);
71 |
72 | /**
73 | * calculate the mFloor of the mPosition
74 | *
75 | * @param position item mPosition
76 | * @return the mFloor
77 | */
78 | HivePositionInfo getFloorOfPosition(int position);
79 |
80 | /**
81 | * calculate all item number int the mFloor
82 | *
83 | * @param floor mFloor
84 | * @return number of the mFloor
85 | */
86 | int getNumberOfFloor(int floor);
87 |
88 | /**
89 | * calculate the Length of regular hexagon
90 | *
91 | * @param rectF the item view bounds
92 | * @param orientation the layout orientation
93 | * @return the length of regular hexagon
94 | */
95 | float calculateLength(@NonNull RectF rectF, @HiveLayoutManager.Orientation int orientation);
96 |
97 | /**
98 | * calculate the Length of regular hexagon
99 | *
100 | * @param rect the item view bounds
101 | * @param orientation the layout orientation
102 | * @return the length of regular hexagon
103 | */
104 | float calculateLength(@NonNull Rect rect, @HiveLayoutManager.Orientation int orientation);
105 |
106 | /**
107 | * calculate current mFloor Rects by last mFloor
108 | *
109 | * @param lastFloorRects Rects at last mFloor
110 | * @param length the length of regular hexagon
111 | * @param floor last mFloor
112 | * @param orientation orientation {@link jack.hive.HiveLayoutManager.Orientation}
113 | * @return RectFs at current mFloor
114 | */
115 | List> mFloors = new ArrayList<>();
76 | private final HiveBucket mBooleanMap = new HiveBucket();
77 | private int mOrientation;
78 | private int mGravity = CENTER;
79 | private boolean firstLayout = true;
80 | private RectF mPadding = new RectF();
81 |
82 | /**
83 | * @param orientation the LayoutManager orientation.
84 | * @see #VERTICAL
85 | * @see #HORIZONTAL
86 | */
87 | public HiveLayoutManager(@Orientation int orientation) {
88 | mOrientation = orientation;
89 | init();
90 | }
91 |
92 | private void init() {
93 | mHiveMathUtils = HiveMathUtils.getInstance();
94 | mLayoutState = new LayoutState();
95 |
96 | mBooleanMap.reset();
97 | }
98 |
99 | public int getGravity() {
100 | return mGravity;
101 | }
102 |
103 | /**
104 | * set the Gravity for the item.
105 | *
106 | * @param gravity
107 | * @see #ALIGN_LEFT
108 | * @see #ALIGN_TOP
109 | * @see #ALIGN_RIGHT
110 | * @see #ALIGN_BOTTOM
111 | * @see #CENTER
112 | *