2018年技术周期计划:周期计划-2(2018/1/8-2018/1/14)
写在前面
写这边文章的时候是2018年1月12日,也就是18年的第二周,按照原计划应该是关于分割线的封装,不过后来想一想既然提到了封装,那不如多写一写,因此有了这个封装系列。
这个系列的开篇是关于Header和Footer的封装思路。
感兴趣的看官,可以看看我的其他文章:
1、常用集合的源码分析:HashMap
2、Java反射实践:从反射中理解class
3、从公司项目配置看Gradle
开始
效果在这里就不浪费篇幅去展示了,估计大家也都知道。
正常思路
给RecyclerView增加头部布局本身不存在什么难度,按照我们正常的流程,写一个符合我们业务逻辑的头部布局的ViewHolder,然后在getItemViewType()里通过position返回一个表示头部布局ViewHolder的Type类型,然后在onCreateItemViewHolder(ViewGroup parent, int viewType)里通过viewType来初始化return我们不同的ViewHolder。
这用做法,肯定是没有什么毛病。但是如果我们需要频繁的使用不同的头部布局,那么我们就要考虑去封装这个问题了。这里简单的提供一种封装的思路,(当然这种思路是存在于弊端的,那就是这种封装是基于业务的封装,系列计划中会有关于抽取的封装思路)如果有更好的思路,欢迎讨论。
封装思路(有点水)
这里提供的思路并不具备可移植性,因为是基于业务本身的封装,所以核心是继承RecyclerView.Adapter并拓展。因为这个项目的本身并不单单是封装Header,而是同样包括了下拉、下拉、分割线等操作。主要还是为了梳理并记录这么一种基于业务的思想。
这里封装的思想,直接延续正常的思路,也就是基于Type的对外封装。
首先,让我们的这个类去继承RecyclerView.Adapter,例如这样:HeaderRecyclerViewAdapter extends RecyclerView.Adapter。
然后在构造方法中传入我们正常的Adapter,然后创建俩个List<View>,用于放置我们的Header以及Footer。
对应的我们要对外暴露相应的add方法:
public void addHeader(View headerView) {
if (!headerViews.contains(headerView)) {
headerViews.add(headerView);
//当然这里可以使用notifyItemChanged(int position)去优化
notifyDataSetChanged();
}
}
给Header设置一个合适的Type,比如:
public static final int VIEW_TYPE_HEADER_OFFSET = Integer.MIN_VALUE;
接下来就是getItemViewType()方法的处理了。
@Override
public int getItemViewType(int position) {
if (!headerViews.isEmpty() && position < headerViews.size()) {
return VIEW_TYPE_HEADER_OFFSET + position;
}
//计算我们常规数据的position,也就是减去Header的List的size的数量即可
if (!headerViews.isEmpty()) {
position -= headerViews.size();
}
//adapter就是我们在构造方法里传进来的RecyclerView.Adapter
if (adapter != null && position < adapter.getItemCount()) {
return adapter.getItemViewType(position);
}
}
return了viewType,那么我们就要处理onCreateViewHolder()方法了。
public static boolean isHeaderView(int viewType) {
return viewType < VIEW_TYPE_HEADER_OFFSET;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
if (isHeaderView(viewType)) {
return new HeaderViewHolder(headerViews.get(viewType - VIEW_TYPE_HEADER_OFFSET));
}
return adapter.onCreateViewHolder(parent, viewType);
}
紧接着就是处理onBindViewHolder()方法。其实这里对于我们来说并不需要处理,因为我们来说,Header的操作应该交由外部处理,因此这里我们return掉,只需要对常规数据的adapter,调用super方法即可。
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
int viewType = getItemViewType(position);
//这里直接return的原因,我们这里不做对Header的处理,交由外部。
if (isHeaderView(viewType)) {
return;
}
position -= headerViews.size();
adapter.onBindViewHolder(holder, position);
}
到这我们的针对Header的封装就算是结束了,使用的时候也很简单,只需要在初始化了这个实现类后调用addHeader方法,传入我们自己的布局即可。(单纯只看这个封装,其实并不能给我们带来多么大的体验,但是如果综合多个功能去封装那所带来的战斗力将不言而喻)
Footer的话,和Header是同理的。
总结
其实单单是为了封装Header本身的意义并不大,就像上诉的列子,并无法给我们带来多么大的便利,但是如果我们综合去封装,就可以发现它存在的意义,比如:我的观公司RecyclerView封装有感中那样,把对应的功能封装到一起,那么作为一个业务的基类,我们将会发现可以很快捷完成不少类似的业务。
2018年7月2号,我正式开始了自己的Android工作,为了能够让自己能够好好完成工作,并且能够快速得到技术提升。所以打算以公众号的方式去敦促自己学习,我会把自己日常的学习笔记发布到公众号上,如果可以,共同进步!~