RecyclerView的功能强大之处就不用说了,但是相比于listview来说,它也有些小缺点,比如:没有了间隔线divider,没有addHeaderView、addFooterView等方法,所以用起来不是那么方便。今天主要完成RecyclerView的addHeaderView和addFooterView方法。
运行效果如下:
第一步:自定义RecyclerView,代码如下:
public class XRecyclerView extends RecyclerView {
//用来存储添加的headerView和footerView
private ArrayList mHeadView = new ArrayList<>();
private ArrayList mFootView = new ArrayList<>();
//RecyclierView的适配器
private Adapter mAdapter;
public XRecyclerView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
//添加头部view,仿ListView的源码改造
public void addHeaderView(View headerView) {
mHeadView.add(headerView);
if (mAdapter != null) {
if (!(mAdapter instanceof HeaderViewRecyclerAdapter)) {
mAdapter = new HeaderViewRecyclerAdapter(mHeadView,mFootView, mAdapter);
}
}
}
//添加脚View
public void addFooterView(View footView) {
mFootView.add(footView);
if (mAdapter != null) {
if (!(mAdapter instanceof HeaderViewRecyclerAdapter)) {
mAdapter = new HeaderViewRecyclerAdapter(mHeadView,mFootView, mAdapter);
}
}
}
@Override
public void setAdapter(Adapter adapter) {
//参考listview方法 setAdapter的源码,对adapter进行更换
if (mHeadView.size() > 0 || mFootView.size() > 0)
mAdapter = new HeaderViewRecyclerAdapter(mHeadView, mFootView, adapter);
else {
mAdapter = adapter;
}
super.setAdapter(mAdapter);
}
}
第二步自定义RecyclerView的adapter,代码如下:
public class HeaderViewRecyclerAdapter extends RecyclerView.Adapter {
private final int HEADER = 1;
private final int FOOTER = 2;
private ArrayList mHeadView;
private ArrayList mFootView;
private RecyclerView.Adapter mAdapter;
public HeaderViewRecyclerAdapter(ArrayList HeadView, ArrayList FootView, RecyclerView.Adapter adapter) {
mAdapter = adapter;
if (HeadView == null) {
//为了防止空指针异常
mHeadView = new ArrayList<>();
} else {
mHeadView = HeadView;
}
if (FootView == null) {
mFootView = new ArrayList<>();
} else {
mFootView = FootView;
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
//头部修改newHeadViewHolder的方法,mFooterView,有几个头,就需要几个headViewHolder
if (viewType == HEADER) {
return new HeadViewHolder(mHeadView.get(0));
} else if (viewType == FOOTER) {
//脚部,修改newHeadViewHolder的方法,mFooterView,有多个
return new FootViewHolder(mFootView.get(0));
}
//body部分,暴露出去操作
return mAdapter.onCreateViewHolder(parent, viewType);
}
//判断view的类型,头,身体,脚
@Override
public int getItemViewType(int position) {
int headcount = getHeadCount();
//返回头部
if (position < headcount) {
//返回头部类型,
return HEADER;
}
//body类型
final int midPosition = position - headcount;
int itemCount = 0;
if (mAdapter != null) {
itemCount = mAdapter.getItemCount();
if (midPosition < itemCount) {
//返回type不要写死了,body的类型可能不一致
return mAdapter.getItemViewType(midPosition);
}
}
//Footer类型
return FOOTER;
}
/**
* 和数据绑定,这里只做body部分的绑定
* 头和脚的数据绑定逻辑都是在外部操作的
* 传入前都已经绑定好l
*/
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
int headcount = getHeadCount();
if (position < headcount) {
//头部数据绑定,外部传入前已经操作,这里不再操作
return;
}
//body数据绑定
final int midPosition = position - headcount;
int itemcount = 0;
if (mAdapter != null) {
itemcount = mAdapter.getItemCount();
if (midPosition < itemcount) {
//暴露出去自由操作,传入的是调整后的位置,而不是算上头角的位置
// mAdapter.onBindViewHolder(holder, position);
mAdapter.onBindViewHolder(holder, midPosition);
return;
}
}
//脚部数据绑定,和头一样,啥也不用操作
}
@Override
public int getItemCount() {
//身体部分不为空
if (mAdapter != null) {
return getHeadCount() + getFootCount() + mAdapter.getItemCount();
} else {
//只有头和脚的情况下
return getHeadCount() + getFootCount();
}
}
private int getFootCount() {
return mFootView.size();
}
public int getHeadCount() {
return mHeadView.size();
}
/**
* 面两个head viewholder 没什么卵用
* viewholder是为了相同的item减少findviewbyid的时间
* 头部holder和尾部holder没有共性的findviewbyid
* 为了拓展方便只得创建,但是不会用到
*/
class HeadViewHolder extends RecyclerView.ViewHolder {
public HeadViewHolder(View itemView) {
super(itemView);
}
}
class FootViewHolder extends RecyclerView.ViewHolder {
public FootViewHolder(View itemView) {
super(itemView);
}
}
}
第三步,就是在activity中使用刚才写的recyclerview,代码如下:
public class MainActivity extends AppCompatActivity {
private XRecyclerView recyclerView;
private List list = new ArrayList<>();
private View headView;
private View footView;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = ((XRecyclerView) findViewById(R.id.recyclerView));
initData();
initHeaderView();
recyclerView.addHeaderView(headView);
recyclerView.addFooterView(footView);
MyAdapter adapter = new MyAdapter(list);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
recyclerView.setAdapter(adapter);
}
private void initHeaderView() {
headView = LayoutInflater.from(this).inflate(R.layout.header, null);
footView = LayoutInflater.from(this).inflate(R.layout.footer, null);
}
private void initData() {
for (int i = 0; i < 10; i++) {
list.add("我是身体body" + i);
}
}
class MyAdapter extends RecyclerView.Adapter {
private List list;
public MyAdapter(List list) {
this.list = list;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(MainActivity.this).inflate(R.layout.item, parent, false);
MyViewHolder holder = new MyViewHolder(itemView);
return holder;
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.text.setText(list.get(position));
}
@Override
public int getItemCount() {
return list.size();
}
class MyViewHolder extends RecyclerView.ViewHolder {
TextView text;
public MyViewHolder(View itemView) {
super(itemView);
text = (TextView) itemView.findViewById(R.id.tv_item);
}
}
}
}
总结:这种方法只能添加一个头和一个脚,本来是想能任意添加头和脚的,后来发现有点问题,
if (viewType == HEADER) {
return new HeadViewHolder(mHeadView.get(0));
} else if (viewType == FOOTER) {
//脚部,修改newHeadViewHolder的方法,mFooterView,有多个
return new FootViewHolder(mFootView.get(0));
}
//body部分,暴露出去操作
return mAdapter.onCreateViewHolder(parent, viewType);
在viewholder创建的时候,头部和尾部也有viewholder,这个对象池不能复用,因为头和脚可以是各种不同类型的***,一旦添加多个头和脚的时候就有问题,这个问题待搞定。