android recycleView 数据分组显示解决方案

作者: aitality | 来源:发表于2018-08-31 18:05 被阅读185次

    最近在开发过程中,遇到这样一个需求,就是对数组分组显示,在网上找了很多方案,但都讲得不全面,在此记录一下自己实践成功的方案。如下图:


    S80831-173502.jpg

    具体步骤

    第一步、使用RecycleView实现,并设置layoutManager为GridLayoutManager。

    int column = Utils.calculateCashBackStoreSpanCount(getContext());
    GridLayoutManager layoutManager = new GridLayoutManager(getContext(), column);
    recycleView.setLayoutManager(layoutManager);
    

    第二步、使adapter支持多类型,例如:
    需要加入开源库
    versions.base_adapter = "3.0.3"
    compile "com.zhy:base-rvadapter:$versions.base_adapter"

    public class StoreGridAdapter extends MultiItemTypeAdapter<Object> {
        public static int ITEM_TYPE_ADS = 2;
        public static int ITEM_TYPE_LABEL = 1;
        public static int ITEM_TYPE_STORE = 0;
    
        public StoreGridAdapter(Context context, List<Object> list) {
            super(context, list);
            addItemViewDelegate(ITEM_TYPE_LABEL, new LabelItemViewDelegate());
            addItemViewDelegate(ITEM_TYPE_STORE, new StoreItemViewDelegate());
            addItemViewDelegate(ITEM_TYPE_ADS, new AdsItemViewDelegate());
        }
    
        class LabelItemViewDelegate implements ItemViewDelegate<Object> {
    
            @Override
            public int getItemViewLayoutId() {
                return R.layout.item_store_first_letter_lay;
            }
    
            @Override
            public boolean isForViewType(Object item, int position) {
                return (item instanceof String);
            }
    
            @Override
            public void convert(ViewHolder holder, Object item, int position) {
                String label = (String) item;
                TextView tv = holder.getView(R.id.text);
                tv.setText(Formatter.toUpperOfFirst(label));
            }
        }
    
        class StoreItemViewDelegate implements ItemViewDelegate<Object> {
            @Override
            public int getItemViewLayoutId() {
                return R.layout.item_grid_store_lay;
            }
    
            @Override
            public boolean isForViewType(Object item, int position) {
                return (item instanceof StoreItem);
            }
    
            @Override
            public void convert(ViewHolder holder, Object o, int position) {
                final StoreItem storeItem = (StoreItem) o;
                ImageView logoImg = holder.getView(R.id.itemStoreLogo);
                TextView cashBackTxt = holder.getView(R.id.itemCashback);
                CommonImageLoader.displayImage(mContext, storeItem.storeLogo, logoImg);
                cashBackTxt.setText(storeItem.cashbackValue);
                holder.getConvertView().setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        onStoreClick(storeItem);
                    }
                });
            }
        }
    
        class AdsItemViewDelegate implements ItemViewDelegate<Object> {
            @Override
            public int getItemViewLayoutId() {
                return R.layout.layout_ads;
            }
    
            @Override
            public boolean isForViewType(Object item, int position) {
                return (item instanceof AdGroup);
            }
    
            @Override
            public void convert(ViewHolder holder, Object o, int position) {
                AdGroup group = (AdGroup) o;
                AdsGroupView adsView = holder.getView(R.id.ads);
                adsView.showAds(group.adGroup);
            }
        }
    
        //计算每一行显示的列数
        @Override
        public void onAttachedToRecyclerView(RecyclerView recyclerView) {
            super.onAttachedToRecyclerView(recyclerView);
            RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
            if(manager instanceof GridLayoutManager) {
                final GridLayoutManager gridManager = ((GridLayoutManager) manager);
                gridManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                    @Override
                    public int getSpanSize(int position) {
                        return (getItemViewType(position) == ITEM_TYPE_LABEL
                                || getItemViewType(position) == ITEM_TYPE_ADS)
                                ? gridManager.getSpanCount() : 1;
                    }
                });
            }
        }
    
        private void onStoreClick(StoreItem storeItem) {
            
        }
    }
    
    

    第三步、计算间距。大概说一下算法:首先识别item是否是label,然后设置label间距;其次计算item所在位置是不是新行开始。代码如下:

    class MyItemDecoration extends RecyclerView.ItemDecoration {
    
            private int space;
            private int spanCount;
    
            MyItemDecoration (int cols, int space){
                this.spanCount = cols;
                this.space = space;
            }
    
            @Override
            public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
                RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
                int position = parent.getChildAdapterPosition(view); // item position
                spanCount = ((GridLayoutManager) layoutManager).getSpanCount();
                if(position == 0) {
                    outRect.top = space;
                }
                if(isAds(parent, position)) {
                    outRect.top = 0;
                    outRect.left = 0;
                    outRect.right = 0;
                }else if(isLabel(parent, position)) {
                    //label
                    outRect.left = space*2;
                    outRect.right = space;
                }else{
                    if(isNewLine(parent, position)) {
                        outRect.left = space;
                        outRect.right = space;
                    }else{
                        outRect.right = space;
                    }
                }
                outRect.bottom = space;
            }
    
            private boolean isLabel(RecyclerView parent, int position){
                int viewType = parent.getAdapter().getItemViewType(position);
                return (viewType == AllStoreGridAdapter.ITEM_TYPE_LABEL);
            }
    
            private boolean isNewLine(RecyclerView parent, int position){
                boolean newLine = false;
                if(isLabel(parent, position-1)){
                    return true;
                }
                int startIndex = findAreaStartIndex(parent, position);
                if(startIndex > -1) {
                    return ((position-1 - startIndex) % spanCount == 0);
                }
                return newLine;
            }
    
            private int findAreaStartIndex(RecyclerView parent, int position){
                for(int i=position; i<= position; i--){
                    if(isLabel(parent, i)){
                        return i;
                    }
                }
                return -1;
            }
    
            private boolean isAds(RecyclerView parent, int position){
                int viewType = parent.getAdapter().getItemViewType(position);
                return (viewType == AllStoreGridAdapter.ITEM_TYPE_ADS);
            }
        }
    

    总结

    RecycleView控件可以绘制出各种各样的布局效果,秘诀就是合理使用layoutManager,动态item的带下和间距。

    相关文章

      网友评论

      • yemoumou:俱往矣,数风流人物,还看今朝。-简书朋友你好,我是币圈一老友,我的写作方向是区块链和数字货币,初到简书,望多多关照。互粉互赞,已赞,期待您的回赞哦。-Қ逥ݗ链剂

      本文标题:android recycleView 数据分组显示解决方案

      本文链接:https://www.haomeiwen.com/subject/wulewftx.html