自定义LayoutManager,实现RecyclerView折叠效果

少废话,先看效果图!

分析

根据效果图我们不难看出:我们需要实现列表的折叠与展开的效果,也就是说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);
    }
}

参考

  1. Android自定义LayoutManager第十一式之飞龙在天
  2. 卡牌堆叠滑动效果,增加回滚动画

你可能感兴趣的:(Android及开发)