少废话,先看效果图!
分析
根据效果图我们不难看出:我们需要实现列表的折叠与展开的效果,也就是说RecylerView需要有两个状态:一个是展开状态,其实展开状态就是常规的LinearLayoutManager;另外一个是折叠的状态,这个就需要我们自定义LayoutManger实现了。
实现
public class StackLayoutManager extends RecyclerView.LayoutManager {
private static final String TAG = "StackLayoutManager";
private static final int MAX_SHOW_COUNT = 3;
private static final int CARD_VERTICAL_GAP = 20;
private Context mContext;
private Rect mViewInfo;
public StackLayoutManager(Context context) {
mContext = context;
}
@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) {
int itemCount = getItemCount();
if (itemCount == 0) {
return;
}
if (state.isPreLayout()) {
return;
}
detachAndScrapAttachedViews(recycler);
for (int i = 0; i < itemCount; i++) {
View view = recycler.getViewForPosition(i);
addView(view);
measureChildWithMargins(view, 0, 0);
detachAndScrapView(view, recycler);
}
LayoutItems(recycler, state);
}
/**
* 回收不需要的Item,并且将需要显示的Item从缓存中取出
*/
private void LayoutItems(RecyclerView.Recycler recycler, RecyclerView.State state) {
// 当数量大于临界点才需要回收view
boolean isMeetNum = getItemCount() >= MAX_SHOW_COUNT + 1;
if (isMeetNum) {
for (int i = MAX_SHOW_COUNT + 1; i < getItemCount(); i++) {
View child = recycler.getViewForPosition(i);
removeAndRecycleView(child, recycler);
}
}
// 展示需要展示的view
for (int i = isMeetNum ? (MAX_SHOW_COUNT) : (getItemCount() - 1); i >= 0; i--) {
View scrap = recycler.getViewForPosition(i);
measureChildWithMargins(scrap, 0, 0);
addView(scrap);
int pointX = i == MAX_SHOW_COUNT ? (MAX_SHOW_COUNT -1) : i;
int widthSpace = getWidth() - getDecoratedMeasuredWidth(scrap);
int heightSpace = getHeight() - getDecoratedMeasuredHeight(scrap);
//设置View的left, top ,right, bottom(根据需求可以得出:折叠的卡片宽度会不断变小)
mViewInfo = new Rect();
int left = widthSpace / 2 + pointX * Utils.dip2px(mContext, 10);
int top = heightSpace / 2;
int right = widthSpace / 2 + getDecoratedMeasuredWidth(scrap) - pointX * Utils.dip2px(mContext, 10);
int bottom = heightSpace / 2 + getDecoratedMeasuredHeight(scrap);
mViewInfo.set(left, top, right, bottom);
//将这个item布局出来
layoutDecorated(scrap, mViewInfo.left , mViewInfo.top, mViewInfo.right , mViewInfo.bottom);
//将Viwe向下平移,营造出折叠的效果
int realI = i == MAX_SHOW_COUNT ? (MAX_SHOW_COUNT - 1) : i;
int translateY = realI * Utils.dip2px(mContext, 10);
ViewCompat.setTranslationY(scrap, translateY);
}
}
@Override
public void onDetachedFromWindow(RecyclerView view, RecyclerView.Recycler recycler) {
super.onDetachedFromWindow(view, recycler);
removeAndRecycleAllViews(recycler);
recycler.clear();
}
@Override
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {
int widthMode = View.MeasureSpec.getMode(widthSpec);
int heightMode = View.MeasureSpec.getMode(heightSpec);
//如果RecyclerView宽度设置了wrap_content,需要指定width
if (widthMode == View.MeasureSpec.AT_MOST) {
widthSpec = View.MeasureSpec.makeMeasureSpec(Utils.dip2px(mContext, 300), View.MeasureSpec.EXACTLY);
}
//如果RecyclerView高度设置了wrap_content
if (heightMode == View.MeasureSpec.AT_MOST) {
heightSpec = View.MeasureSpec.makeMeasureSpec(getHeight(), View.MeasureSpec.EXACTLY);
}
super.onMeasure(recycler, state, widthSpec, heightSpec);
}
}