Skip to content

Commit e16a4f2

Browse files
committed
add support for vertical
1 parent eb2abbb commit e16a4f2

File tree

3 files changed

+117
-23
lines changed

3 files changed

+117
-23
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ Demonstrate how to custom `RecycleView#LayoutManager`
66

77
### v1.0
88

9+
A LinearLayoutManager like LayoutManager, Horizontal and Vertical support.
10+
911
## License
1012

1113
```

app/src/main/java/github/hellocsl/gallerylayoutmanager/MainActivity.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import android.os.Bundle;
44
import android.support.v7.app.AppCompatActivity;
5-
import android.support.v7.widget.LinearLayoutManager;
65
import android.support.v7.widget.RecyclerView;
76
import android.view.View;
87
import android.view.ViewGroup;
@@ -59,8 +58,9 @@ public void onItemClick(View view, int position) {
5958
});
6059
mMainRecycle1.setAdapter(demoAdapter1);
6160

62-
LinearLayoutManager layoutManager2 = new LinearLayoutManager(this);
63-
layoutManager2.setOrientation(LinearLayoutManager.VERTICAL);
61+
// LinearLayoutManager layoutManager2 = new LinearLayoutManager(this);
62+
// layoutManager2.setOrientation(LinearLayoutManager.VERTICAL);
63+
GalleryLayoutManager layoutManager2 = new GalleryLayoutManager(this, GalleryLayoutManager.VERTICAL);
6464
mMainRecycle2.setLayoutManager(layoutManager2);
6565
DemoAdapter demoAdapter2 = new DemoAdapter(title) {
6666
@Override

app/src/main/java/github/hellocsl/gallerylayoutmanager/layout/GalleryLayoutManager.java

Lines changed: 112 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,8 @@
1919
public class GalleryLayoutManager extends RecyclerView.LayoutManager {
2020
private static final String TAG = "GalleryLayoutManager";
2121
private final Context mContext;
22-
/* Consistent size applied to all child views */
23-
// private int mDecoratedChildWidth;
24-
// private int mDecoratedChildHeight;
25-
26-
// private int mSelectionPosition = 0;
2722
private int mFirstVisiblePosition = -1;
2823
private int mLastVisiblePos = -1;
29-
// private int mSelectedIndex;
3024

3125

3226
public static final int HORIZONTAL = OrientationHelper.HORIZONTAL;
@@ -103,11 +97,103 @@ private void fillCover(RecyclerView.Recycler recycler, RecyclerView.State state,
10397

10498
}
10599

106-
100+
/**
101+
* @param recycler
102+
* @param state
103+
* @param dy
104+
*/
107105
private void fillWithVertical(RecyclerView.Recycler recycler, RecyclerView.State state, int dy) {
108-
// TODO: 2016/11/19
106+
int topEdge = getOrientationHelper().getStartAfterPadding();
107+
int bottomEdge = getOrientationHelper().getEndAfterPadding();
108+
109+
//1.根据滑动方向,回收越界子View
110+
View child;
111+
if (getChildCount() > 0) {
112+
if (dy >= 0) {
113+
for (int i = 0; i < getChildCount(); i++) {
114+
child = getChildAt(i);
115+
if (getDecoratedBottom(child) - dy < topEdge) {
116+
removeAndRecycleView(child, recycler);
117+
mFirstVisiblePosition++;
118+
} else {
119+
break;
120+
}
121+
}
122+
} else { //dy<0
123+
for (int i = getChildCount() - 1; i >= 0; i--) {
124+
child = getChildAt(i);
125+
if (getDecoratedTop(child) - dy > bottomEdge) {
126+
removeAndRecycleView(child, recycler);
127+
mLastVisiblePos--;
128+
}
129+
}
130+
}
131+
132+
}
133+
//开始进行布局的位置
134+
int startPosition = mFirstVisiblePosition;
135+
int startOffset = -1;
136+
int scrapWidth, scrapHeight;
137+
Rect scrapRect = new Rect();
138+
int width = getHorizontalSpace();
139+
int leftOffset;
140+
View scrap;
141+
//2.根据不同滑动方向,为空余位置进行布局
142+
if (dy >= 0) {
143+
if (getChildCount() != 0) {
144+
View lastView = getChildAt(getChildCount() - 1);
145+
startPosition = getPosition(lastView) + 1; //下一个View的Position
146+
startOffset = getDecoratedBottom(lastView);
147+
}
148+
//考虑边界和数量
149+
for (int i = startPosition; i < getItemCount() && startOffset < bottomEdge; i++) {
150+
scrap = recycler.getViewForPosition(i);
151+
addView(scrap);
152+
measureChildWithMargins(scrap, 0, 0);
153+
scrapWidth = getDecoratedMeasuredWidth(scrap);
154+
scrapHeight = getDecoratedMeasuredHeight(scrap);
155+
leftOffset = (int) (getPaddingLeft() + (width - scrapWidth) / 2.0f);
156+
if (startOffset == -1 && startPosition == 0) {
157+
//第0个View,居中处理
158+
int top = (int) (getPaddingLeft() + (getHorizontalSpace() - scrapWidth) / 2.f);
159+
scrapRect.set(leftOffset, top, leftOffset + scrapWidth, top + scrapHeight);
160+
} else {
161+
scrapRect.set(leftOffset, startOffset, leftOffset + scrapWidth, startOffset + scrapHeight);
162+
}
163+
layoutDecorated(scrap, scrapRect.left, scrapRect.top, scrapRect.right, scrapRect.bottom);
164+
startOffset = scrapRect.bottom;
165+
((LayoutParams) scrap.getLayoutParams()).mPosition = i;
166+
mLastVisiblePos = i;
167+
getState().mItemsFrames.put(i, scrapRect);
168+
if (BuildConfig.DEBUG) {
169+
Log.d(TAG, "fillWithHorizontal,layout:mLastVisiblePos: " + mLastVisiblePos);
170+
}
171+
}
172+
} else {
173+
//dy<0
174+
if (getChildCount() > 0) {
175+
View firstView = getChildAt(0);
176+
startPosition = getPosition(firstView) - 1; //前一个View的position
177+
startOffset = getDecoratedTop(firstView);
178+
}
179+
//考虑边界和数量
180+
for (int i = startPosition; i >= 0 && startOffset > topEdge; i--) {
181+
scrapRect = getState().mItemsFrames.get(i);
182+
scrap = recycler.getViewForPosition(i);
183+
addView(scrap, 0);
184+
measureChildWithMargins(scrap, 0, 0);
185+
scrapWidth = scrapRect.right - scrapRect.left;
186+
scrapHeight = scrapRect.bottom - scrapRect.top;
187+
leftOffset = (int) (getPaddingLeft() + (width - scrapWidth) / 2.0f);
188+
layoutDecorated(scrap, leftOffset, startOffset - scrapHeight, leftOffset + scrapWidth, startOffset);
189+
startOffset -= scrapHeight;
190+
((LayoutParams) scrap.getLayoutParams()).mPosition = i;
191+
mFirstVisiblePosition = i;
192+
}
193+
}
109194
}
110195

196+
111197
/**
112198
* @param recycler
113199
* @param state
@@ -247,13 +333,9 @@ class State {
247333
*/
248334
int mScrollDelta;
249335

250-
int mInitOffset;
251-
252-
253336
public State() {
254337
mItemsFrames = new SparseArray<Rect>();
255338
mScrollDelta = 0;
256-
mInitOffset = 0;
257339
}
258340
}
259341

@@ -303,17 +385,27 @@ public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, Recycler
303385

304386
@Override
305387
public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
306-
if (getChildCount() == 0) {
388+
if (getChildCount() == 0 || dy == 0) {
307389
return 0;
308390
}
309-
final View topView = getChildAt(0);
310-
final View bottomView = getChildAt(getChildCount() - 1);
311-
312-
int viewSpan = getDecoratedBottom(bottomView) - getDecoratedTop(topView);
313-
if (viewSpan < getVerticalSpace()) {
314-
return 0;
391+
int delta = -dy;
392+
int parentCenter = (getOrientationHelper().getEndAfterPadding() - getOrientationHelper().getStartAfterPadding()) / 2 + getOrientationHelper().getStartAfterPadding();
393+
View child;
394+
if (dy > 0) { //手势左滑
395+
if (((LayoutParams) getChildAt(getChildCount() - 1).getLayoutParams()).mPosition == getItemCount() - 1) {
396+
child = getChildAt(getChildCount() - 1);
397+
delta = -Math.max(0, Math.min(dy, (child.getBottom() - child.getTop()) / 2 + child.getTop() - parentCenter));
398+
}
399+
} else {
400+
if (mFirstVisiblePosition == 0) {
401+
child = getChildAt(0);
402+
delta = -Math.min(0, Math.max(dy, ((child.getBottom() - child.getTop()) / 2 + child.getTop()) - parentCenter));
403+
}
315404
}
316-
return super.scrollVerticallyBy(dy, recycler, state);
405+
getState().mScrollDelta = -delta;
406+
fillCover(recycler, state, -delta);
407+
offsetChildrenVertical(delta);
408+
return -delta;
317409
}
318410

319411
private OrientationHelper getOrientationHelper() {

0 commit comments

Comments
 (0)