这不最近再研究自定义LayoutManager么,想来想去也没有好的创意,就先拿它开第一刀吧。
(后话:流式布局Item宽度不一,不知不觉给自己挖了个大坑,造成拓展一些功能难度倍增,观之网上的DEMO,99%Item的大小都是一样的,so,这个系列的下一篇我计划 实现一个Item大小一样 的酷炫LayoutManager。但是最终做成啥样的效果还没想好,有朋友看到酷炫的效果可以告诉我,我去高仿一个。)
自定义LayoutManager的步骤:
以本文的流式布局为例,需求是一个垂直滚动的布局,子View以流式排列。先总结一下步骤:
一 实现 generateDefaultLayoutParams()
二 实现 onLayoutChildren()
三 竖直滚动需要 重写canScrollVertically()和scrollVerticallyBy()
下面我们就一步一步来吧。
二 实现generateDefaultLayoutParams()
=================================
如果没有特殊需求,大部分情况下,我们只需要如下重写该方法即可。
@Override
public RecyclerView.LayoutParams generateDefaultLayoutParams() {
return new RecyclerView.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
}
RecyclerView.LayoutParams
是继承自android.view.ViewGroup.MarginLayoutParams
的,所以可以方便的使用各种margin。
这个方法最终会在recycler.getViewForPosition(i)
时调用到,在该方法浩长源码的最下方:
final ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
final LayoutParams rvLayoutParams;
if (lp == null) {
//这里会调用mLayout.generateDefaultLayoutParams()为每个ItemView设置LayoutParams
rvLayoutParams = (LayoutParams) generateDefaultLayoutParams();
holder.itemView.setLayoutParams(rvLayoutParams);
} else if (!checkLayoutParams(lp)) {
rvLayoutParams = (LayoutParams) generateLayoutParams(lp);
holder.itemView.setLayoutParams(rvLayoutParams);
} else {
rvLayoutParams = (LayoutParams) lp;
}
rvLayoutParams.mViewHolder = holder;
rvLayoutParams.mPendingInvalidate = fromScrap && bound;
return holder.itemView;
重写完这个方法就能编译通过了,只不过然并卵,界面上是一片空白,下面我们就走进onLayoutChildren()
方法 ,为界面添加Item。
注:99%用不到的情况:如果需要存储一些额外的东西在LayoutParams
里,这里返回你自定义的LayoutParams
即可。
当然,你自定义的LayoutParams
需要继承自RecyclerView.LayoutParams
。
三 onLayoutChildren()
====================
该方法是LayoutManager的入口。它会在如下情况下被调用:
1 在RecyclerView初始化时,会被调用两次。
2 在调用adapter.notifyDataSetChanged()时,会被调用。
3 在调用setAdapter替换Adapter时,会被调用。
4 在RecyclerView执行动画时,它也会被调用。
即RecyclerView 初始化 、 数据源改变时 都会被调用。