RecyclerView实现流式布局并添加headerview、footerview

之所以写这篇文章,是因为今天在面试的时候,被问到了。当然早在1年前,我就在项目中大量使用了RecyclerView。后来换了新的公司之后,就基本没怎么用了。没想到被面试官问了怎么添加header和footer,勉强答出来了。结果人家加了一句,如果LayoutManager是流式布局,或者GridLayoutManager的话,header会出现留白的问题,怎么处理啦?这个还真没用过,所以就干脆研究了一下。

  private class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.Holder> {
        private List<Integer> heightList;
        //item类型
        public static final int ITEM_TYPE_HEADER = 0;
        public static final int ITEM_TYPE_CONTENT = 1;
        public static final int ITEM_TYPE_FOOTER = 2;

        public View getFooterView() {
            return footerView;
        }

        public void setFooterView(View footerView) {
            this.footerView = footerView;
        }

        public View getHeaderView() {
            return headerView;
        }

        public void setHeaderView(View headerView) {
            this.headerView = headerView;
        }

        private View headerView;
        private View footerView;

        public CustomAdapter() {
            heightList = new ArrayList<>();
            for(int i = 0; i < dataList.size(); i ++ ) {
                heightList.add((int) (100 + Math.random()*300));
            }
        }

        @Override
        public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = null;
            if(viewType == ITEM_TYPE_CONTENT) {
                view = mInflater.inflate(R.layout.layout_item,null);
            }else if(viewType == ITEM_TYPE_HEADER) {
                view = headerView;
            }else {
                view = footerView;
            }
            return new Holder(view);
        }

        @Override
        public void onBindViewHolder(Holder holder, int position) {
                if(getItemViewType(position) == ITEM_TYPE_CONTENT) {
                   if(headerView != null) {
                       position -= 1;
                   }
                   int data = dataList.get(position);
                   holder.dataTXT.setText(data + "");
                   ViewGroup.LayoutParams params = holder.mLinearLayout.getLayoutParams();
                   params.height = heightList.get(position);
                   holder.mLinearLayout.setLayoutParams(params);
               }
        }

        @Override
        public void onViewAttachedToWindow(Holder holder) {
            super.onViewAttachedToWindow(holder);
            ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
            if(lp != null && lp instanceof StaggeredGridLayoutManager.LayoutParams) {
                StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
                p.setFullSpan(holder.getItemViewType() == ITEM_TYPE_HEADER || holder.getItemViewType() == ITEM_TYPE_FOOTER);
            }
        }

        @Override
        public int getItemViewType(int position) {
            if(headerView == null && footerView == null) {
                return ITEM_TYPE_CONTENT;
            }
            if(position == 0 && headerView != null) {
                return ITEM_TYPE_HEADER;
            }else if(position == getItemCount() - 1 && footerView != null) {
                return ITEM_TYPE_FOOTER;
            }else {
                return ITEM_TYPE_CONTENT;
            }
        }


        @Override
        public int getItemCount() {
            return dataList.size() + (headerView == null ? 0 : 1) + (footerView == null ? 0 : 1);
        }

        class Holder extends RecyclerView.ViewHolder {
            private LinearLayout mLinearLayout;
            private TextView dataTXT;
            public Holder(View itemView) {
                super(itemView);
                mLinearLayout = (LinearLayout) itemView.findViewById(R.id.lly);
                dataTXT = (TextView) itemView.findViewById(R.id.data_txt);
            }
        }
    }

上面这段代码,关键的地方在getItemViewType(int position)这个方法中,正常情况下,我们是不需要重写这个方法的。当我们需要给RecyclerView添加header或者footer的时候,就需要用到这个方法了。可以看到在自定义Adapter时,我们定义了3个字段分别代表item的3种类型:ITEM_TYPE_HEADER、ITEM_TYPE_FOOTER、ITEM_TYPE_CONTENT。在这个方法里面,我们通过position来判断,当position=0时,就返回ITEM_TYPE_HEADER代表头视图,当position=getItemCount() - 1时,就返回ITEM_TYPE_FOOTER代表尾视图,其他则返回ITEM_TYPE_CONTENT,代表是普通的item视图。
然后我们在onCreateViewHolder()方法中,根据ViewType来判断应该传入哪一种布局。
这样我们添加header和footer的问题就解决了。但是正常情况下,我们在项目中的头布局和尾部局肯定都是单独占一行,这个我们要怎么解决啦?
要解决这个问题,我们就需要去重写onViewAttachedToWindow()这个方法了。

  @Override
        public void onViewAttachedToWindow(Holder holder) {
            super.onViewAttachedToWindow(holder);
            ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
            if(lp != null && lp instanceof StaggeredGridLayoutManager.LayoutParams) {
                StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
                p.setFullSpan(holder.getItemViewType() == ITEM_TYPE_HEADER || holder.getItemViewType() == ITEM_TYPE_FOOTER);
            }
        }

这里我们获取itemview的layoutparams,然后调用setFullSpan来让它占满全整行空间。就可以达到我们想要的效果啦!
这里写图片描述

部分参考:http://blog.csdn.net/qibin0506/article/details/49716795

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值