LayoutManager已經(jīng)有很多博客分享過自定義的方法和注意事項(xiàng),目前我也在學(xué)習(xí)顺少,不班門弄斧講原理朋其。這個(gè)效果是在一個(gè)app上看到的,直接上實(shí)現(xiàn)代碼脆炎,有需要的可以參考一下梅猿。
public class ScatteredLayoutManager extends RecyclerView.LayoutManager {
private int verticalScrollOffset;
private int offsetH = 0;
private int leftMargin, rightMargin;
@Override
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
return new RecyclerView.LayoutParams(RecyclerView.LayoutParams.WRAP_CONTENT, RecyclerView.LayoutParams.WRAP_CONTENT);
}
@Override
public boolean isAutoMeasureEnabled() {
return true;
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
super.onLayoutChildren(recycler, state);
if (getItemCount() == 0) {
detachAndScrapAttachedViews(recycler);
return;
}
if (getChildCount() == 0 && state.isPreLayout()) {
return;
}
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
recycler.getViewForPosition(0).getLayoutParams();
leftMargin = params.leftMargin;
rightMargin = params.rightMargin;
//先把所有item從RecyclerView中detach
detachAndScrapAttachedViews(recycler);
layoutItem(recycler);
}
private void layoutItem(RecyclerView.Recycler recycler) {
offsetH = getPaddingTop();
int width = (Resources.getSystem().getDisplayMetrics().widthPixels
- getRightDecorationWidth(recycler.getViewForPosition(0))
- getLeftDecorationWidth(recycler.getViewForPosition(0))
- leftMargin - rightMargin) / 3;
int round = 0;
for (int i = 0; i < getItemCount(); i++) {
View view = recycler.getViewForPosition(i);
addView(view); // 因?yàn)閐etach過所以重新添加
measureChildWithMargins(view, 0, 0);
int height = getDecoratedMeasuredHeight(view);
Rect mTmpRect = new Rect();
calculateItemDecorationsForChild(view, mTmpRect);
switch (i - round) {
case 0:
layoutDecoratedWithMargins(view, 0, offsetH, 2 * width, offsetH + height);
break;
case 1:
layoutDecoratedWithMargins(view, 2 * width, offsetH,
3 * width, offsetH + height / 2);
break;
case 2:
layoutDecoratedWithMargins(view, 2 * width, offsetH + height / 2,
3 * width, offsetH + height);
offsetH = offsetH + height;
break;
case 3:
layoutDecoratedWithMargins(view, 0, offsetH,
width, offsetH + height / 2);
break;
case 4:
layoutDecoratedWithMargins(view, 0, offsetH + height / 2,
width, offsetH + height);
break;
case 5:
layoutDecoratedWithMargins(view, width, offsetH,
3 * width, offsetH + height);
offsetH = offsetH + height;
break;
default:
layoutDecoratedWithMargins(view, 0, offsetH, 3 * width,
offsetH + height);
offsetH = offsetH + height;
break;
}
if (i + 1 - round == 6)
round += 6;
}
}
@Override
public boolean canScrollVertically() {
return true;
}
@Override
public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
//列表向下滾動(dòng)dy為正,列表向上滾動(dòng)dy為負(fù)秒裕,這點(diǎn)與Android坐標(biāo)系保持一致袱蚓。
//實(shí)際要滑動(dòng)的距離
int travel = dy;
//如果滑動(dòng)到最頂部
if (verticalScrollOffset + dy < 0) {
travel = -verticalScrollOffset;
} else if (verticalScrollOffset + dy > offsetH - getVerticalSpace()) {//如果滑動(dòng)到最底部
travel = offsetH - getVerticalSpace() - verticalScrollOffset;
}
//將豎直方向的偏移量+travel
verticalScrollOffset += travel;
// 調(diào)用該方法通知view在y方向上移動(dòng)指定距離
offsetChildrenVertical(-travel);
return travel;
}
private int getVerticalSpace() {
//計(jì)算RecyclerView的可用高度,除去上下Padding值
return getHeight() - getPaddingBottom() - getPaddingTop();
}
}
說明:目前只是將item的布局實(shí)現(xiàn)几蜻,并且讓列表滾動(dòng)起來喇潘,還沒時(shí)間去寫復(fù)用的代碼和一些優(yōu)化,有時(shí)間會(huì)更新梭稚。