RecyclerView-->添加头布局和底布局

RecyclerView-->添加头布局和底布局_第1张图片

效果图:


RecyclerView-->添加头布局和底布局_第2张图片

参考文章:
Android 优雅的为RecyclerView添加HeaderView和FooterView

该功能主要是对adapter使用了装饰者模式,具体代码看下面的分析:

  • HeaderAndFooterActivity.java
public class HeaderAndFooterActivity extends AppCompatActivity {

    @BindView(R.id.recyclerView)
    RecyclerView mRecyclerView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_header_and_footer);
        ButterKnife.bind(this);
        setTitle("添加Header和Footer");
        //创建处理正常数据的adapter
        HeaderAndFotterAdapter adapter = new HeaderAndFotterAdapter(this);
        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
        //创建负责处理Header和footer的adpapter
        HeaderAndFooterWrapper headerAndFooterWrapper = new HeaderAndFooterWrapper(adapter);
        TextView t1 = new TextView(this);
        t1.setText("Header 1");
        TextView t2 = new TextView(this);
        t2.setText("Header 2");
        TextView t3 = new TextView(this);
        t3.setText("Header 3");
        TextView t4 = new TextView(this);
        t4.setText("Header 4");
        headerAndFooterWrapper.addHeaderView(t1);
        headerAndFooterWrapper.addHeaderView(t2);
        headerAndFooterWrapper.addFooterView(t3);
        headerAndFooterWrapper.addFooterView(t4);
        mRecyclerView.setLayoutManager(linearLayoutManager);
        //RecyclerView的Adapter被赋值为headerAndFooterWrapper,
        // 而正常处理数据的adapter在headerAndFooterWrapper中被调用
        mRecyclerView.setAdapter(headerAndFooterWrapper);
    }
}

上面代码很简单,主要就是初始化两个adpater和创建头布局和底布局。

  • HeaderAndFooterWrapper.java
public class HeaderAndFooterWrapper  extends RecyclerView.Adapter{
    public static final int BASE_ITEM_TYPE_HEADER = 100000;
    public static final int BASE_ITEM_TYPE_FOOTER = 200000;
    private SparseArrayCompat mHeaderViews = new SparseArrayCompat<>();
    private SparseArrayCompat mFooterViews = new SparseArrayCompat<>();

    private RecyclerView.Adapter mInnerAdapter;

    public HeaderAndFooterWrapper(RecyclerView.Adapter innerAdapter) {
        mInnerAdapter = innerAdapter;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (mHeaderViews.get(viewType) != null){
            return new MyViewHolder(mHeaderViews.get(viewType));
        }else if (mFooterViews.get(viewType) != null){
            return new MyViewHolder(mFooterViews.get(viewType));
        }
        return mInnerAdapter.onCreateViewHolder(parent,viewType);
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (isHeaderViewPos(position))
            return;
        if (isFooterViewPos(position))
            return;
        mInnerAdapter.onBindViewHolder(holder,position - getHeadersCount());
    }

    @Override
    public int getItemCount() {
        return getHeadersCount() + getFootersCount() + getRealItemCount();
    }

    @Override
    public int getItemViewType(int position) {
        if (isHeaderViewPos(position)){
            return mHeaderViews.keyAt(position);
        }else if (isFooterViewPos(position)){
            return mFooterViews.keyAt(position - getHeadersCount() - getRealItemCount());
        }
        return mInnerAdapter.getItemViewType(position - getHeadersCount());
    }

    /**
     * 获取正常数据的size
     * @return
     */
    private int getRealItemCount(){
        return mInnerAdapter.getItemCount();
    }

    /**
     * 判断是否是Header
     * @param position
     * @return
     */
    private boolean isHeaderViewPos(int position){
        return position < getHeadersCount();
    }

    /**
     * 判断是否是Footer
     * @param position
     * @return
     */
    private boolean isFooterViewPos(int position){
        return position >= getHeadersCount() + getRealItemCount();
    }


    public void addHeaderView(View view){
        mHeaderViews.put(mHeaderViews.size() + BASE_ITEM_TYPE_HEADER,view);
    }
    public void addFooterView(View view){
        mFooterViews.put(mFooterViews.size() + BASE_ITEM_TYPE_FOOTER,view);
    }
    private int getHeadersCount(){
        return mHeaderViews.size();
    }
    public int getFootersCount(){
        return mFooterViews.size();
    }

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

上面我们使用了线性布局,如果我们使用了网格和瀑布流,就有可能出问题咯,比如头布局不能占据一行的问题。


RecyclerView-->添加头布局和底布局_第3张图片

下面是关于适配网格和瀑布流布局的解决方案:
在HeaderAndFooterWrapper.java中重写下面的方法:

    /**
     * 适配网格布局
     * @param recyclerView
     */
    @Override
    public void onAttachedToRecyclerView(RecyclerView recyclerView) {
        mInnerAdapter.onAttachedToRecyclerView(recyclerView);
        final RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
        if (layoutManager instanceof GridLayoutManager){
            final GridLayoutManager gridLayoutManager = (GridLayoutManager) layoutManager;
            gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
                @Override
                public int getSpanSize(int position) {
                    return isHeaderViewPos(position) || isFooterViewPos(position) ? ((GridLayoutManager) layoutManager).getSpanCount() : 1;
                }
            });
        }
    }

上面只解决了网格布局的,下面我们在HeaderAndFooterWrapper.java中可以重写onViewAttachedToWindow方法解决瀑布流的问题。

    @Override
    public void onViewAttachedToWindow(RecyclerView.ViewHolder holder) {

        mInnerAdapter.onViewAttachedToWindow(holder);
        int position = holder.getLayoutPosition();
        if (isHeaderViewPos(position)||isFooterViewPos(position)){
            ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
            if (lp != null && lp instanceof StaggeredGridLayoutManager.LayoutParams){
                StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
                p.setFullSpan(true);
            }
        }
    }

完整demo地址

你可能感兴趣的:(RecyclerView-->添加头布局和底布局)