RecyclerView封装——添加Header、Footer(在网格瀑布流布局中独占一行)

转载请标明出处:
http://blog.csdn.net/sinat_15877283/article/details/50913998
本文出自: 【温利东的博客】


前言 FOREWORD

  • 很多人(包括我)已经开始抛弃ListView和GridView转为RecyclerView了。
    网络上有很多关于RecyclerView加头加尾的文章,其中组合模式占多,这种模式大概思路是自定义一个customView 然后在里面放置 一个头布局容器、一个尾布局容器,一个RecyclerView容器 :
    这里写图片描述

这种写法太low了…..原本recyclerView层级就很深了,这相当于在加深了一层,碰上稍微复杂一些的item,手机不是要卡到爆吗?这让低端机怎么活!!!

  • 最近在看《App研发录》这本书籍,感觉之前对recyclerView封装的不到位,借此完善一下。

正文 BODY

说说本篇文章需要解决的问题,了解需求我们才能有针对性的进行封装:

  • 可为RecyclerView 添加/移除 多个Header和Footer
  • 解决HeaderView、FooterView在网格/瀑布流中 布局不足一行问题
  • 可拓展、低耦合

行为封装: IAdapter< VH, M>:

/**
 * Created by wenld- on 2016/3/17.
 */
public interface IAdapter<VH, M> {
    /** 设置 主内容 View类型  */
    int getAdvanceViewType(int position);

    /**  加头View  */
    void addHeaderView(View headerView);

    /**   加尾View  */
    void addFooterView(View footerView);

    /**  数据绑定View  */
    void onBindAdvanceViewHolder(VH holder, int i);

    /**   加载 ViewGroup 容器  */
    RecyclerView.ViewHolder onCreateAdvanceViewHolder(ViewGroup parent, int viewType);
}

需要事先了解的技术点

  public int getItemViewType(int position) {...}
    @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) % HeaderFooterFlag == 0)
                            ? gridManager.getSpanCount() : 1;
                }
            });
        }
    }

    @Override
    public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
        super.onViewAttachedToWindow(holder);
        ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
        if (lp != null
                && lp instanceof StaggeredGridLayoutManager.LayoutParams
                && holder.getLayoutPosition() == 0) {
            StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
            p.setFullSpan(true);
        }
    }
  • 判断View类型: public int getItemViewType(int position)
  • 让头尾View在 GridLayoutManager,StaggeredGridLayoutManager布局中 占用1行

封装篇 AdvancedAdapter:

/**
 * Created by wenld- on 2015/9/24.
 * <p/>
 * 简单封装 加头加尾 recyclerView 适配器
 * 在布局 GridLayoutManager,StaggeredGridLayoutManager  头尾占一行
 */
public abstract class AdvancedAdapter<VH extends AdvancedAdapter.ViewHolder, M>
        extends RecyclerView.Adapter<RecyclerView.ViewHolder>
        implements IAdapter<VH, M> {
    private ArrayList<View> mHeaderViews = new ArrayList<>();
    private ArrayList<View> mFooterViews = new ArrayList<>();
    protected ItemClickInterface<M> listener;
    protected List<M> mData;

    public final void addHeaderView(View headerView) {
        mHeaderViews.add(headerView);
    }
    public final void addFooterView(View footerView) {
        mFooterViews.add(footerView);
    }

    private SparseIntArray mHeaderViewTypes = new SparseIntArray();
    private SparseIntArray mFooterViewTypes = new SparseIntArray();
    private final static int HeaderFooterFlag = 100000;

    @Override
        public int getItemViewType(int position) {
        if (mHeaderViews.size() > 0 && position < mHeaderViews.size()) {
            //用position作为HeaderView 的   ViewType标记
            //记录每个ViewType标记
            position = (position + 1) * HeaderFooterFlag;
            mHeaderViewTypes.put(position, position);
            return position;
        }

        if (mFooterViews.size() > 0 && position > getAdvanceCount() - 1 + mHeaderViews.size()) {
            //用position作为FooterView 的   ViewType标记
            position = (position + 1) * HeaderFooterFlag;
            mHeaderViewTypes.put(position, position);
            return position;
        }

        return getAdvanceViewType(position);
    }

    /**
     * @return
     */
    public int getAdvanceCount() {
        int a = 0;
        if (mData != null) {
            a = mData.size();
        }
        return a;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (mHeaderViewTypes.get(viewType, -1) != (-1)) {
            return new HeaderHolder(mHeaderViews.get(viewType / 100000 - 1));
        }

        if (mFooterViewTypes.get(viewType, -1) != (-1)) {
            int index = viewType / 100000 - 1 - getAdvanceCount() - mHeaderViews.size();
            return new FooterHolder(mFooterViews.get(index));
        }

        return onCreateAdvanceViewHolder(parent, viewType);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

        if (mFooterViews.size() > 0 && (position > getAdvanceCount() - 1 + mHeaderViews.size())) {
            return;
        }

        if (mHeaderViews.size() > 0) {
            if (position < mHeaderViews.size()) {
                return;
            }
            onBindAdvanceViewHolder((VH) holder, position - mHeaderViews.size());
            return;
        }
        onBindAdvanceViewHolder((VH) holder, position - mHeaderViews.size());
    }

    class HeaderHolder extends RecyclerView.ViewHolder {
        public HeaderHolder(View itemView) {
            super(itemView);
        }
    }

    class FooterHolder extends RecyclerView.ViewHolder {
        public FooterHolder(View itemView) {
            super(itemView);
        }
    }

    public abstract class ViewHolder extends RecyclerView.ViewHolder implements IViewHolder {
        public ViewHolder(View itemView) {
            super(itemView);
        }
        public int getAdpPosition() {
            return Selected(getAdapterPosition());
        }
    }

    public M getItem(int position) {
        if (getItemCount() == 0) {
            return null;
        }
        return mData.get(position);
    }

    @Override
    public int getItemCount() {
        if (mHeaderViews.size() > 0 && mFooterViews.size() > 0) {
            return getAdvanceCount() + mHeaderViews.size() + mFooterViews.size();
        }
        if (mHeaderViews.size() > 0) {
            return getAdvanceCount() + mHeaderViews.size();
        }
        if (mFooterViews.size() > 0) {
            return getAdvanceCount() + mFooterViews.size();
        }

        return getAdvanceCount();
    }

    public int Selected(int position) {
        if (mHeaderViews.size() > 0 && position < mHeaderViews.size()) {
            return -1;
        }
        if (mFooterViews.size() > 0 && position > getAdvanceCount() - 1 + mHeaderViews.size()) {
            return -1;
        } else {
            return position - mHeaderViews.size();
        }
    }

    @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) % HeaderFooterFlag == 0)
                            ? gridManager.getSpanCount() : 1;
                }
            });
        }
    }

    @Override
    public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {
        super.onViewAttachedToWindow(holder);
        ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
        if (lp != null
                && lp instanceof StaggeredGridLayoutManager.LayoutParams
                && holder.getLayoutPosition() == 0) {
            StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
            p.setFullSpan(true);
        }
    }

    @Override
    public void setData(List<M> mDataList) {
        this.mData = mDataList;
    }

    @Override
    public List<M> getData() {
        return mData;
    }

    @Override
    public void setListener(ItemClickInterface<M> listener) {
        this.listener = listener;
    }
}

使用篇:MyAdapter:

/**
 * Created by wenld- on 2016/3/17.
 */
public class MyAdapter extends AdvancedAdapter<ImageListAdapter.ViewHolder, ImagesListEntity> {
    private Context mContext;

    @Override
    public int getAdvanceViewType(int position) {
        return position;
    }

    @Override
    public void onBindAdvanceViewHolder(ViewHolder holder, int i) {
      .....
    }

    @Override
    public RecyclerView.ViewHolder onCreateAdvanceViewHolder(ViewGroup parent, int viewType) {
        ViewHolder vh = .....
        return vh;
    }

    public MyAdapter (Context mContext, List<ImagesListEntity> mData, ItemClickInterface listener) {
        ...
    }

    public class ViewHolder extends AdvancedAdapter.ViewHolder {
        public ImageView icon;

        public ViewHolder(View v) {
            super(v);
            v.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if (listener != null) {
                        listener.onItemClick(mData.get(getAdpPosition()), getAdpPosition());
                    }
                }
            });
            icon = (ImageView) v.findViewById(R.id.list_item_images_list_image);
        }
    }
}

结论

样式做的不好看,但这不是重点…..(哈哈哈哈,随手加了一个TextView)

这里写图片描述


对于控件类的封装最好不要用组合模式!!!
对于控件类的封装最好不要用组合模式!!!
对于控件类的封装最好不要用组合模式!!!
重要的事情说三遍………
demo 戳这里、戳!戳!戳!

希望我的分享能对你有帮助,也希望你能提出你的意见和想法,一起分享,共同成长。
转载请标明出处: http://blog.csdn.net/sinat_15877283/article/details/50913998

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值