仿照Listview 优雅实现 RecyclerView的 HeaderView 和 FootView

来源:互联网 发布:包月无限流量软件 编辑:程序博客网 时间:2024/05/17 01:33

前言:

作为一个Listview的进阶产品 RecyclerView在很多时候使用起来并不是那么方便,而其中addFootViewaddHeaderView使用起来远没有 Listview的一句话来的简单,而目前大多数博文提供的思路都是在BaseAdapterViewType来做文章,这样做确实可以很好的实现我们想要的效果,而今天,我们就在这个基础上来进行一次封装,使得我们使用的方式变成下面这样

 recyclerView.addFootView(R.layout.foot_item); recyclerView.addHeaderView(R.layout.header_item); recyclerView.setLayoutManager(new LinearLayoutManager(this,LinearLayoutManager.VERTICAL,false)); recyclerView.setAdapter(adapter)

通过上面,我们大概能知道,我们是自定义了一个RecyclerView,其余的用法和原生的 RecyclerView是没有什么区别的,如果你感兴趣,那么,就接着往下看吧。。。

分析

上面的效果到底是怎么实现的呢?恩?聪明的你有没有想到ListView呢?然后你去翻看ListView源码,我们可以发现,他的实现其实和我们想的应该是差不多的,通过一个HeaderViewListAdapter将我们setAdapter的适配器包裹起来,然后内部就可以通过我们的ViewType来加载headerViewFootView了,恩?这叫什么模式来着。。。应该是装饰者模式。。。哈哈,原来如此简单,只是我们不容易想到而已,那么接下来,我们就来撸一把。。。

撸码

其实想到了这个方法,那么接下来的撸码过程应该是很简单的,这里我只考虑 LinearLayoutManager这个布局管理器了,如果你要实现其他两种布局管理器的foot和header,可以去看看鸿洋大神的博客,Ok,多的不说了,直接贴代码。

import android.content.Context;import android.support.annotation.LayoutRes;import android.support.annotation.Nullable;import android.support.v7.widget.RecyclerView;import android.util.AttributeSet;import android.view.LayoutInflater;import android.view.ViewGroup;import java.util.ArrayList;import java.util.List;public class FootHeaderRecyclerView extends RecyclerView {    //这里我们保存的是 layoutId 方便 createViewHolder    List<Integer> mHeaders = new ArrayList<>();    List<Integer> mFoots = new ArrayList<>();    private Adapter mAdapter;    public FootHeaderRecyclerView(Context context) {        super(context);    }    public FootHeaderRecyclerView(Context context, @Nullable AttributeSet attrs) {        super(context, attrs);    }    public FootHeaderRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {        super(context, attrs, defStyle);    }    public void addHeaderView(@LayoutRes int layoutId) {        checkAdapter();        mHeaders.add(layoutId);    }    private void checkAdapter() {        if (!(mAdapter == null || mAdapter instanceof AdapterWrapper)) {            throw new IllegalStateException("please call addHeaderView or addFootView before setAdapter");        }    }    public void addFootView(@LayoutRes int layoutId) {        checkAdapter();        mFoots.add(layoutId);    }    //关键在这里我们对 adapter 进行了包装    @Override    public void setAdapter(Adapter adapter) {        Adapter adapter1;        if (mFoots.size() != 0 || mHeaders.size() != 0) {             adapter1 = new AdapterWrapper(adapter);             super.setAdapter(adapter1);        } else {            super.setAdapter(adapter);            adapter1 = adapter;        }        mAdapter =adapter1;    }    private class AdapterWrapper extends Adapter {        RecyclerView.Adapter adapter;        public AdapterWrapper(Adapter adapter) {            this.adapter = adapter;        }        @Override        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {            LayoutInflater inflater = LayoutInflater.from(parent.getContext());            if (mHeaders.contains(viewType) || mFoots.contains(viewType)) {                return new ViewHolder(inflater.inflate(viewType, parent, false)) {                };            } else {                return   adapter.createViewHolder(parent, viewType);            }        }        @Override        public void onBindViewHolder(ViewHolder holder, int position) {            //此处应该注意!!!            // 和 listview 一样这里的 position 是包含了 foot 和 header 的            adapter.onBindViewHolder(holder, position);        }        @Override        public int getItemCount() {            return adapter.getItemCount() + mHeaders.size() + mFoots.size();        }        //稍微有点障碍的可能就是这个 position 的计算了,当然,其实也很简单,代两个数进去计算就好了        @Override        public int getItemViewType(int position) {            if (position < mHeaders.size()) {                //header size                return mHeaders.get(position);            }            if (position >= mHeaders.size() && position < adapter.getItemCount() + mHeaders.size()) {                return adapter.getItemViewType(position - mHeaders.size());            }            if (position >= getItemCount() - mFoots.size()) {                return mFoots.get(position - mHeaders.size() - adapter.getItemCount());            }            throw new RuntimeException("unknown error position");        }    }}

结束语

今天分享这个,应该算是最简单的,但也不能算是简单,如果不是带着问题去看了ListView的源码,我觉的我肯定是想不出这个方法来实现的,记得以前看源码,是为了看源码而看源码,往往看来看去,也不知所云,而带着某种目的或者疑问去看源码,就会发现,很多东西都变的清晰,变的有迹可循,最重要的你会发现,看源码再也不是枯燥无味的事情了,而是那么的吸引着你。。。好了,最后,还是希望本文对你有一点帮助

阅读全文
0 0
原创粉丝点击