android之装饰设计模式

定义

在不使用继承的前提下,动态的扩展一个类的功能,就叫做装饰设计模式

背景

android里面使用装饰设计模式的有Context,ListView添加和删除头部尾部布局,还有IO流等等。那么到底如何动态的扩展一个类的功能呢?

实例
recyclerview在项目当中是使用的最多的控件之一,经常要添加头部或者尾部,那么如何一劳永逸的让recyclerview都能支持头部和尾部布局呢?
  • 第一步
    首先继承自Recyclerview.Adapter,并且用两个集合来装载头部和尾部布局
public class DecorRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

	// 原来的recyclerview.Adapter,并不支持头部和底部的添加
	private RecyclerView.Adapter	mRealAdapter;

	private List<View>				mHeadViewList	= new ArrayList<>();

	private List<View>				mFooterList		= new ArrayList<>();

	public DecorRecyclerAdapter(RecyclerView.Adapter adapter) {
		this.mRealAdapter = adapter;
	}
	
	public void addHeadView(View headView) {
		if (!mHeadViewList.contains(headView)) {
			mHeadViewList.add(headView);
			notifyDataSetChanged();
		}
	}

	public void addFooterView(View footerView) {
		if (!mFooterList.contains(footerView)) {
			mFooterList.add(footerView);
			notifyDataSetChanged();
		}
	}

	public void removeHeadView(View headView) {
		if (mHeadViewList.contains(headView)) {
			mHeadViewList.remove(headView);
			notifyDataSetChanged();
		}
	}

	public void removeFooterView(View footerView) {
		if (mFooterList.contains(footerView)) {
			mFooterList.remove(footerView);
			notifyDataSetChanged();
		}
	}
}

因为我们将头部和尾部布局添加到recyclerview中了,所以返回的getItemCount就需要修改成下边这样

@Override public int getItemCount() {
		return mHeadViewList.size() + mRealAdapter.getItemCount() + mFooterList.size();
	}
  • 第二步
    当我们使用onCreateViewHolder方法的时候,需要区分是头部,还是真实的Adapter还是尾部:
@Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int position) {
		// 头部返回头部的viewHolder
		// 真实的adapter返回真实的viewHolder
		// 底部返回底部的viewHolder

		int numHeaders = getHeadersCount();
		if (position < numHeaders) {
			return createHeaderOrFooterViewHolder(mHeadViewList.get(position));
		}

		// Adapter
		final int adjPosition = position - numHeaders;
		int adapterCount = 0;
		if (mRealAdapter != null) {
			adapterCount = mRealAdapter.getItemCount();
			if (adjPosition < adapterCount) {
				return mRealAdapter.onCreateViewHolder(parent, mRealAdapter.getItemViewType(adjPosition));
			}
		}

		// Footer (off-limits positions will throw an IndexOutOfBoundsException)
		return createHeaderOrFooterViewHolder(mFooterList.get(adjPosition - adapterCount));
	}

	private RecyclerView.ViewHolder createHeaderOrFooterViewHolder(View view) {
		return new RecyclerView.ViewHolder(view) {};
	}

	public int getHeadersCount() {
		return mHeadViewList.size();
	}

	/***
	 * 将position作为viewType传递给onCreateViewHolder
	 * 
	 * @param position
	 *            位置
	 * @return viewType
	 */
	@Override public int getItemViewType(int position) {
		return position;
	}
  • 第三步
    在onBindViewHolder的时候,如果是头部或尾部,则无需处理
@Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
		int numHeaders = getHeadersCount();
		if (position < numHeaders) {
			return;
		}

		// Adapter
		final int adjPosition = position - numHeaders;
		int adapterCount = 0;
		if (mRealAdapter != null) {
			adapterCount = mRealAdapter.getItemCount();
			if (adjPosition < adapterCount) {
				mRealAdapter.onBindViewHolder(holder, position);
			}
		}
	}
  • 第四步
    其实上边的代码就已经能够使用了,但是使用的时候,每一个recyclerview设置adapter的时候,都需要包装在DecorRecyclerviewAdapter里面,所以我们需要包装一下Recyclerview。
public class DecorRecyclerview extends RecyclerView {

	private DecorRecyclerAdapter decorRecyclerAdapter;

	public DecorRecyclerview(Context context) {
		this(context, null);
	}

	public DecorRecyclerview(Context context, @Nullable AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public DecorRecyclerview(Context context, @Nullable AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

	@Override public void setAdapter(Adapter adapter) {
		decorRecyclerAdapter = new DecorRecyclerAdapter(adapter);
		super.setAdapter(decorRecyclerAdapter);
	}

	public void addHeadView(View view) {
		if (decorRecyclerAdapter != null) {
			decorRecyclerAdapter.addHeadView(view);
		}
	}

	public void addFooterView(View view) {
		if (decorRecyclerAdapter != null) {
			decorRecyclerAdapter.addFooterView(view);
		}
	}
}
  • 使用
    在MainActivity中使用如下
/**
 * // 业务逻辑层,能分开就分开,比如说注册页面和绑定用户手机页面,就是非常相似的业务逻辑,一定不要去封装 // 不包含业务逻辑的,一定要封装
 * Created by wuxiaojun on 2018/11/22.
 */

public class RecyclerviewActivity extends Activity {

	private DecorRecyclerview	id_recyclerview;

	private List<String>		mList	= new ArrayList<>();

	@Override protected void onCreate(@Nullable Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_recycler);

		for (int i = 0; i < 100; i++) {
			mList.add("position=" + i);
		}

		id_recyclerview = (DecorRecyclerview) findViewById(R.id.id_recyclerview);
		id_recyclerview.addItemDecoration(new DividerItemDecoration(this, LinearLayout.VERTICAL));
		id_recyclerview.setLayoutManager(new LinearLayoutManager(this));

		MyAdapter adapter = new MyAdapter();
		id_recyclerview.setAdapter(adapter);
		View view = LayoutInflater.from(this).inflate(R.layout.item_head, id_recyclerview, false);
		id_recyclerview.addHeadView(view);

	}

	private class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {

		@Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
			View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_text, parent, false);

			return new MyViewHolder(view);
		}

		@Override public void onBindViewHolder(MyViewHolder holder, final int position) {
			holder.textView.setText("position=" + mList.get(position));

			holder.textView.setOnClickListener(new View.OnClickListener() {

				@Override public void onClick(View v) {
					mList.remove(position);
					notifyDataSetChanged();
				}
			});
		}

		@Override public int getItemCount() {
			return mList.size();
		}

	}

	private class MyViewHolder extends RecyclerView.ViewHolder {

		public TextView textView;

		public MyViewHolder(View itemView) {
			super(itemView);

			textView = (TextView) itemView.findViewById(R.id.id_info);
		}
	}

}

如上,装饰设计模式就已经完成了,其实在不继承的前提下,扩展A类的功能就是通过构造方法将A作为参数传递到DecorA中,然后再DecorA里面添加一些A所没有的功能。就是这么简单。
所以代码如下

public class DecorRecyclerAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

	// 原来的recyclerview.Adapter,并不支持头部和底部的添加
	private RecyclerView.Adapter	mRealAdapter;

	private List<View>				mHeadViewList	= new ArrayList<>();

	private List<View>				mFooterList		= new ArrayList<>();

	public DecorRecyclerAdapter(RecyclerView.Adapter adapter) {
		this.mRealAdapter = adapter;

		// 当在mRealAdapter中改变数据的时候,得让DecorRecyclerAdapter也刷新
		mRealAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {

			@Override public void onChanged() {
				notifyDataSetChanged();
			}
		});
	}

	@Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int position) {
		// 头部返回头部的viewHolder

		// 真实的adapter返回真实的viewHolder

		// 底部返回底部的viewHolder

		int numHeaders = getHeadersCount();
		if (position < numHeaders) {
			return createHeaderOrFooterViewHolder(mHeadViewList.get(position));
		}

		// Adapter
		final int adjPosition = position - numHeaders;
		int adapterCount = 0;
		if (mRealAdapter != null) {
			adapterCount = mRealAdapter.getItemCount();
			if (adjPosition < adapterCount) {
				return mRealAdapter.onCreateViewHolder(parent, mRealAdapter.getItemViewType(adjPosition));
			}
		}

		// Footer (off-limits positions will throw an IndexOutOfBoundsException)
		return createHeaderOrFooterViewHolder(mFooterList.get(adjPosition - adapterCount));
	}

	private RecyclerView.ViewHolder createHeaderOrFooterViewHolder(View view) {
		return new RecyclerView.ViewHolder(view) {};
	}

	public int getHeadersCount() {
		return mHeadViewList.size();
	}

	/***
	 * 将position作为viewType传递给onCreateViewHolder
	 * 
	 * @param position
	 *            位置
	 * @return viewType
	 */
	@Override public int getItemViewType(int position) {
		return position;
	}

	@Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
		int numHeaders = getHeadersCount();
		if (position < numHeaders) {
			return;
		}

		// Adapter
		final int adjPosition = position - numHeaders;
		int adapterCount = 0;
		if (mRealAdapter != null) {
			adapterCount = mRealAdapter.getItemCount();
			if (adjPosition < adapterCount) {
				mRealAdapter.onBindViewHolder(holder, position);
			}
		}
	}

	@Override public int getItemCount() {
		return mHeadViewList.size() + mRealAdapter.getItemCount() + mFooterList.size();
	}

	public void addHeadView(View headView) {
		if (!mHeadViewList.contains(headView)) {
			mHeadViewList.add(headView);
			notifyDataSetChanged();
		}
	}

	public void addFooterView(View footerView) {
		if (!mFooterList.contains(footerView)) {
			mFooterList.add(footerView);
			notifyDataSetChanged();
		}
	}

	public void removeHeadView(View headView) {
		if (mHeadViewList.contains(headView)) {
			mHeadViewList.remove(headView);
			notifyDataSetChanged();
		}
	}

	public void removeFooterView(View footerView) {
		if (mFooterList.contains(footerView)) {
			mFooterList.remove(footerView);
			notifyDataSetChanged();
		}
	}

}

猜你喜欢

转载自blog.csdn.net/u010648159/article/details/85331477