2019-04-12设计模式-装饰模式
2019-04-12 本文已影响0人
猫KK
动态地将责任附加到对象上。想要拓展原对象地功能,而不想使用继承;也就是说,我在原来的对象上拓展空能,但是我又不想修改原来对象的代码也不想使用继承,可以考虑使用装饰模式
这里通过拓展RecyclerView的Adapter来实现RecyclerView添加头部尾部地功能,进而学习装饰模式
新建一个装饰类
//注意,装饰类需要和被装饰的类继承同样的超类或实现同样的接口
public class WrapRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private RecyclerView.Adapter mAdapter;
//构造方法,传入需要装饰的对象
public WrapRecyclerAdapter(RecyclerView.Adapter adapter) {
this.mAdapter = adapter;
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder t, int position) {
}
@Override
public int getItemCount() {
}
}
这样,就是生成了一个装饰RecyclerView.Adapter的类,值得注意的是,装饰类的构造方法一般都需要传入被装饰的对象。接下来继续完善,增加添加移除头部、尾部的方法,并使用List保存
public class WrapRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private RecyclerView.Adapter mAdapter;
private ArrayList<View> mHeaderViews;
private ArrayList<View> mFooterViews;
//构造方法,传入需要装饰的对象
public WrapRecyclerAdapter(RecyclerView.Adapter adapter) {
this.mAdapter = adapter;
mHeaderViews = new ArrayList<>();
mFooterViews = new ArrayList<>();
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder t, int position) {
}
@Override
public int getItemCount() {
}
/**
* 增加头部view
*
* @param header
*/
public void addHeaderView(View header) {
if (!mHeaderViews.contains(header)) {
mHeaderViews.add(header);
notifyDataSetChanged();
}
}
/**
* 增加底部view
*
* @param footer
*/
public void addFooterView(View footer) {
if (!mFooterViews.contains(footer)) {
mFooterViews.add(footer);
notifyDataSetChanged();
}
}
/**
* 移除头部view
*
* @param header
*/
public void removeHeaderView(View header) {
if (mHeaderViews.contains(header)) {
mHeaderViews.remove(header);
notifyDataSetChanged();
}
}
/**
* 移除底部view
*
* @param footer
*/
public void removeFooterView(View footer) {
if (mFooterViews.contains(footer)) {
mFooterViews.remove(footer);
notifyDataSetChanged();
}
}
}
继续完善剩下的方法。getItemCount 返回的item的条数,即为原来adapter的条数加上头部尾部的条数
@Override
public int getItemCount() {
return mAdapter.getItemCount() + mHeaderViews.size() + mFooterViews.size();
}
还有两个方法,我们不知道怎么完善,可以去参考ListView的方式,ListView自带有增加头部、尾部的功能,使用的也类似的方法,看ListView.setAdapter()方法
@Override
public void setAdapter(ListAdapter adapter) {
//判断是否有头部或则尾部
if (mHeaderViewInfos.size() > 0|| mFooterViewInfos.size() > 0) {
//有就使用wrapHeaderListAdapterInternal
mAdapter = wrapHeaderListAdapterInternal(mHeaderViewInfos, mFooterViewInfos, adapter);
} else {
mAdapter = adapter;
}
}
其实也是使用了一个装饰类wrapHeaderListAdapterInternal来实现添加头部尾部的功能,去看getItem 方法
public Object getItem(int position) {
// Header (negative positions will throw an IndexOutOfBoundsException)
int numHeaders = getHeadersCount();
if (position < numHeaders) {
return mHeaderViewInfos.get(position).data;
}
// Adapter
final int adjPosition = position - numHeaders;
int adapterCount = 0;
if (mAdapter != null) {
adapterCount = mAdapter.getCount();
if (adjPosition < adapterCount) {
return mAdapter.getItem(adjPosition);
}
}
// Footer (off-limits positions will throw an IndexOutOfBoundsException)
return mFooterViewInfos.get(adjPosition - adapterCount).data;
}
根据position来返回不同的view。根据这个,我们可以仿照这写
//注意这里将viewType当作了position 使用,是因为在getItemViewType中直接返回了position
//需要注意的是,当使用一些多布局时,修改了getItemViewType 的值,可能会出现错误
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int position) {
// Header (negative positions will throw an IndexOutOfBoundsException)
int numHeaders = getHeadersCount();
if (position < numHeaders) {
//如果是头部,直接new RecyclerView.ViewHolder,返回头部的View
return createHeaderOrFooterViewHolder(mHeaderViews.get(position));
}
// Adapter
final int adjPosition = position - numHeaders;
int adapterCount = 0;
if (mAdapter != null) {
adapterCount = mAdapter.getItemCount();
if (adjPosition < adapterCount) {
//如果是原来的,直接调用原来的onCreateViewHolder方法
return mAdapter.onCreateViewHolder(viewGroup, mAdapter.getItemViewType(adjPosition));
}
}
// 尾部同头部
return createHeaderOrFooterViewHolder(mFooterViews.get(adjPosition - adapterCount));
}
@Override
public int getItemViewType(int position) {
return position;
}
private RecyclerView.ViewHolder createHeaderOrFooterViewHolder(View view) {
return new RecyclerView.ViewHolder(view) {
};
}
private int getHeadersCount() {
return mHeaderViews.size();
}
//同onCreateViewHolder方法
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder t, int position) {
int numHeaders = getHeadersCount();
if (position < numHeaders) {
return;
}
final int adjPosition = position - numHeaders;
int adapterCount = 0;
if (mAdapter != null) {
adapterCount = mAdapter.getItemCount();
if (adjPosition < adapterCount) {
mAdapter.onBindViewHolder(t, position);
}
}
}
到这里,装饰类就书写完成,在Activity中使用
rv_decoration.layoutManager = LinearLayoutManager(this)
var adapter = TestAdapter()
//创建装饰类,将原来的对象传进去
var wrapAdapter = WrapRecyclerAdapter(adapter)
rv_decoration.adapter = wrapAdapter
var heardView = LayoutInflater.from(this@DecorationModeActivity).inflate(R.layout.layout_title, rv_decoration, false)
wrapAdapter.addHeaderView(heardView)
var footerView = LayoutInflater.from(this@DecorationModeActivity).inflate(R.layout.layout_title, rv_decoration, false)
wrapAdapter.addFooterView(footerView)
到这里就可以为RecyclerView添加头部和尾部,并且不需要修改原来的代码,这就是装饰模式的好处。
需要注意的是,这个WrapRecyclerAdapter 还是有一点小问题的,但我们只是用来学习装饰模式,就不过多的讲解了。