package org.loader.layoutmanager;
import android.graphics.Rect;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
/**
* Created by qibin on 16-9-25.
*/
public class CardLayoutManager extends RecyclerView.LayoutManager {
public static final int DEFAULT_GROUP_SIZE = 5;
private int mGroupSize;
private int mHorizontalOffset;
private int mVerticalOffset;
private int mTotalWidth;
private int mTotalHeight;
private int mGravityOffset;
private boolean isGravityCenter;
private Pool<Rect> mItemFrames;
public CardLayoutManager(boolean center) {
this(DEFAULT_GROUP_SIZE, center);
}
public CardLayoutManager(int groupSize, boolean center) {
mGroupSize = groupSize;
isGravityCenter = center;
mItemFrames = new Pool<>(new Pool.New<Rect>() {
@Override
public Rect get() { return new Rect();}
});
}
@Override
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
}
@Override
public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {
if (getItemCount() <= 0 || state.isPreLayout()) { return;}
detachAndScrapAttachedViews(recycler);
View first = recycler.getViewForPosition(0);
measureChildWithMargins(first, 0, 0);
int itemWidth = getDecoratedMeasuredWidth(first);
int itemHeight = getDecoratedMeasuredHeight(first);
int firstLineSize = mGroupSize / 2 + 1;
int secondLineSize = firstLineSize + mGroupSize / 2;
if (isGravityCenter && firstLineSize * itemWidth < getHorizontalSpace()) {
mGravityOffset = (getHorizontalSpace() - firstLineSize * itemWidth) / 2;
} else {
mGravityOffset = 0;
}
for (int i = 0; i < getItemCount(); i++) {
Rect item = mItemFrames.get(i);
float coefficient = isFirstGroup(i) ? 1.5f : 1.f;
int offsetHeight = (int) ((i / mGroupSize) * itemHeight * coefficient);
// 每一组的第一行
if (isItemInFirstLine(i)) {
int offsetInLine = i < firstLineSize ? i : i % mGroupSize;
item.set(mGravityOffset + offsetInLine * itemWidth, offsetHeight, mGravityOffset + offsetInLine * itemWidth + itemWidth,
itemHeight + offsetHeight);
}else {
int lineOffset = itemHeight / 2;
int offsetInLine = (i < secondLineSize ? i : i % mGroupSize) - firstLineSize;
item.set(mGravityOffset + offsetInLine * itemWidth + itemWidth / 2,
offsetHeight + lineOffset, mGravityOffset + offsetInLine * itemWidth + itemWidth + itemWidth / 2,
itemHeight + offsetHeight + lineOffset);
}
}
mTotalWidth = Math.max(firstLineSize * itemWidth, getHorizontalSpace());
int totalHeight = getGroupSize() * itemHeight;
if (!isItemInFirstLine(getItemCount() - 1)) { totalHeight += itemHeight / 2;}
mTotalHeight = Math.max(totalHeight, getVerticalSpace());
fill(recycler, state);
}
private void fill(RecyclerView.Recycler recycler, RecyclerView.State state) {
if (getItemCount() <= 0 || state.isPreLayout()) { return;}
Rect displayRect = new Rect(mHorizontalOffset, mVerticalOffset,
getHorizontalSpace() + mHorizontalOffset,
getVerticalSpace() + mVerticalOffset);
/* Rect rect = new Rect();
for (int i = 0; i < getChildCount(); i++) {
View item = getChildAt(i);
rect.left = getDecoratedLeft(item);
rect.top = getDecoratedTop(item);
rect.right = getDecoratedRight(item);
rect.bottom = getDecoratedBottom(item);
if (!Rect.intersects(displayRect, rect)) {
removeAndRecycleView(item, recycler);
}
}*/
for (int i = 0; i < getItemCount(); i++) {
Rect frame = mItemFrames.get(i);
if (Rect.intersects(displayRect, frame)) {
View scrap = recycler.getViewForPosition(i);
addView(scrap);
measureChildWithMargins(scrap, 0, 0);
layoutDecorated(scrap, frame.left - mHorizontalOffset, frame.top - mVerticalOffset,
frame.right - mHorizontalOffset, frame.bottom - mVerticalOffset);
}
}
//你缓存了啥?复用了啥? 跟自定义ViewGroup有什么区别?答案:有,更复杂了。。。。
Log.d("TAG", "count= [" + getChildCount() + "]"+",[recycler.getScrapList().size():"+recycler.getScrapList().size());
}
@Override
public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {
detachAndScrapAttachedViews(recycler);
if (mVerticalOffset + dy < 0) {
dy = -mVerticalOffset;
} else if (mVerticalOffset + dy > mTotalHeight - getVerticalSpace()) {
dy = mTotalHeight - getVerticalSpace() - mVerticalOffset;
}
offsetChildrenVertical(-dy);
fill(recycler, state);
mVerticalOffset += dy;
return dy;
}
@Override
public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler, RecyclerView.State state) {
detachAndScrapAttachedViews(recycler);
if (mHorizontalOffset + dx < 0) {
dx = -mHorizontalOffset;
} else if (mHorizontalOffset + dx > mTotalWidth - getHorizontalSpace()) {
dx = mTotalWidth - getHorizontalSpace() - mHorizontalOffset;
}
offsetChildrenHorizontal(-dx);
fill(recycler, state);
mHorizontalOffset += dx;
return dx;
}
@Override
public boolean canScrollVertically() {
return true;
}
@Override
public boolean canScrollHorizontally() {
return true;
}
private boolean isItemInFirstLine(int index) {
int firstLineSize = mGroupSize / 2 + 1;
return index < firstLineSize || (index >= mGroupSize && index % mGroupSize < firstLineSize);
}
private int getGroupSize() {
return (int) Math.ceil(getItemCount() / (float)mGroupSize);
}
private boolean isFirstGroup(int index) {
return index < mGroupSize;
}
private int getHorizontalSpace() {
return getWidth() - getPaddingLeft() - getPaddingRight();
}
private int getVerticalSpace() {
return getHeight() - getPaddingTop() - getPaddingBottom();
}
}