android之装饰设计模式

本文详细介绍装饰者设计模式在Android RecyclerView控件中的应用,通过具体实例展示了如何动态地为RecyclerView添加头部和尾部布局,实现功能扩展。文章提供完整的代码实现,包括自定义Adapter和RecyclerView子类,以简化头部和尾部布局的添加过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

定义

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

背景

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();
		}
	}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值