装饰设计模式也称为包装设计模式,用来动态的扩展对象的功能,也是继承关系的一种替代方案之一,也就是说在不是用继承的方式下,采用装饰设计模式可以扩展一个对象的功能,可以是一个对象变得越来越强大。源码中就有很多地方用到了装饰设计模式,IO流、ContextCompat、ListView等,ListView的添加头部和底部就是采用装饰设计模式来实现的,而RecyclerView没有添加头部和底部,其实ListView也只不过是系统给实现了而已,既然这样可以参考ListView添加头部和底部的方式来给RecyclerView添加头部和底部。先写一个普通的RecyclerView列表效果,在这效果上面进行添加;
class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(MainActivity.this).inflate(R.layout.adapter_item, parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
holder.tvItem.setText(list.get(position));
holder.tvItem.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this,"点击了"+position,Toast.LENGTH_LONG).show();
}
});
}
@Override
public int getItemCount() {
return list.size();
}
class ViewHolder extends RecyclerView.ViewHolder {
public TextView tvItem;
public ViewHolder(View itemView) {
super(itemView);
tvItem= (TextView) itemView.findViewById(R.id.tv_item);
}
}
}
这个就是最常见的RecyclerView的adapter,接着定义一个adapter继承自RecyclerView.Adapter 并通过该构造方法传入一个adapter;
/**
* Created by Administrator on 2019/1/12.
* RecyclerView adapter 添加头部和底部
*/
public class WrapRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private RecyclerView.Adapter mAdapter;
//存储头部
private ArrayList<View> mHeaderView;
//存储底部
private ArrayList<View> mFooterView;
public WrapRecyclerAdapter(RecyclerView.Adapter adapter) {
this.mAdapter = adapter;
mHeaderView = new ArrayList<>();
mFooterView = new ArrayList<>();
this.mAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
@Override
public void onChanged() {
super.onChanged();
//更新数据
notifyDataSetChanged();
}
});
}
}
在WrapRecyclerAdapter中新增添加头部/删除头部、添加底部/删除底部的方法;
/**
* 添加头部
*
* @param view
*/
public void addHeaderView(View view) {
if (!mHeaderView.contains(view)) {
mHeaderView.add(view);
notifyDataSetChanged();
}
}
/**
* 添加底部
*
* @param view
*/
public void addFooterView(View view) {
if (!mFooterView.contains(view)) {
mFooterView.add(view);
notifyDataSetChanged();
}
}
/**
* 移除头部
*
* @param view
*/
public void removeHeaderView(View view) {
if (mHeaderView.contains(view)) {
mHeaderView.remove(view);
notifyDataSetChanged();
}
}
/**
* 移除底部
*
* @param view
*/
public void removeFooterView(View view) {
if (mFooterView.contains(view)) {
mFooterView.remove(view);
notifyDataSetChanged();
}
}
接下来在创建ViewHolder时就要根据position的位置进行判断,如果是头部就床架头部的ViewHolder,内容就创建内容的ViewHolder,底部就创建底部的ViewHolder;
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int position) {
int headerCount = getHeaderCount();
if (position < headerCount) {
//头部
return createHeaderViewHolder(mHeaderView.get(position));
}
int adjPosition = position - headerCount;
int adapterCount = 0;
if (mAdapter != null) {
//内容区域
adapterCount = mAdapter.getItemCount();
if (adjPosition < adapterCount) {
return mAdapter.onCreateViewHolder(parent,mAdapter.getItemViewType(adjPosition));
}
}
//底部
return createFooterViewHolder(mFooterView.get(adjPosition - adapterCount));
}
/**
* 创建头部viewholder
*
* @param view
*/
private RecyclerView.ViewHolder createHeaderViewHolder(View view) {
return new RecyclerView.ViewHolder(view) {
};
}
/**
* 创建底部viewholder
*
* @param view
* @return
*/
private RecyclerView.ViewHolder createFooterViewHolder(View view) {
return new RecyclerView.ViewHolder(view) {
};
}
在绑定参数时头部和底部就不需要进行处理,只需要处理内容区域就可以了;
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
int numHeaders = getHeaderCount();
if (position < numHeaders) {
//如果是头部直接返回
return;
}
final int adjPosition = position - numHeaders;
int adapterCount = 0;
if (mAdapter != null) {
adapterCount = mAdapter.getItemCount();
if (adjPosition < adapterCount) {
mAdapter.onBindViewHolder(holder,adjPosition);
}
}
}
使用时,在实例化头部或底部view时,parent的传入,要传入当前的RecyclerView;
recyclerView = (RecyclerView) findViewById(R.id.id_recyclerview);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
RecyclerAdapter recyclerAdapter = new RecyclerAdapter();
WrapRecyclerAdapter adapter=new WrapRecyclerAdapter(recyclerAdapter);
recyclerView.setAdapter(adapter);
View headerView = LayoutInflater.from(this).inflate(R.layout.adapter_header, recyclerView, false);
//添加头部
adapter.addHeaderView(headerView);
View footerView = LayoutInflater.from(this).inflate(R.layout.adapter_header, recyclerView, false);
//添加底部
adapter.addFooterView(footerView);
这样就可以对RecyclerView进行添加头部或者底部了,但是每次使用的时候都需要创建两个adapter,有点麻烦,并且这样子调用也不符合迪米特原则(最少知识原则),最好能弄成ListView那样就最好了;那就继续往下走吧,自定义一个RecyclerView,重写setAdaper方法,并新增添加头部/删除头部、添加底部/删除底部的方法;
public class WrapRecyclerView extends RecyclerView {
private WrapRecyclerAdapter mAdapter;
public WrapRecyclerView(Context context) {
this(context, null);
}
public WrapRecyclerView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public WrapRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public void setAdapter(Adapter adapter) {
mAdapter = new WrapRecyclerAdapter(adapter);
super.setAdapter(mAdapter);
}
/**
* 添加头部
*
* @param view
*/
public void addHeaderView(View view) {
if (mAdapter!=null) {
mAdapter.addHeaderView(view);
}
}
/**
* 添加底部
*
* @param view
*/
public void addFooterView(View view) {
if (mAdapter!=null) {
mAdapter.addFooterView(view);
}
}
/**
* 移除头部
*
* @param view
*/
public void removeHeaderView(View view) {
if (mAdapter!=null) {
mAdapter.removeHeaderView(view);
}
}
/**
* 移除底部
*
* @param view
*/
public void removeFooterView(View view) {
if (mAdapter!=null) {
mAdapter.removeFooterView(view);
}
}
}
需要注意,必须要设置了adapter才可以添加头部和底部;
recyclerView = (WrapRecyclerView) findViewById(R.id.id_recyclerview);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
RecyclerAdapter recyclerAdapter = new RecyclerAdapter();
//WrapRecyclerAdapter adapter=new WrapRecyclerAdapter(recyclerAdapter);
recyclerView.setAdapter(recyclerAdapter);
View headerView = LayoutInflater.from(this).inflate(R.layout.adapter_header, recyclerView, false);
//添加头部
recyclerView.addHeaderView(headerView);
View footerView = LayoutInflater.from(this).inflate(R.layout.adapter_header, recyclerView, false);
//添加底部
recyclerView.addFooterView(footerView);
这样子就和ListView的添加头部和底部使用一样了。