裝飾設計模式也稱爲包裝設計模式,用來動態的擴展對象的功能,也是繼承關係的一種替代方案之一,也就是說在不是用繼承的方式下,採用裝飾設計模式可以擴展一個對象的功能,可以是一個對象變得越來越強大。源碼中就有很多地方用到了裝飾設計模式,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的添加頭部和底部使用一樣了。