mFirstVisiPos = 0;
mLastVisiPos = getItemCount();
//初始化时调用 填充childView
fill(recycler, state);
}
这个fill(recycler, state);
方法将是你自定义LayoutManager之旅一生的敌人,简单的说它承担了以下任务:
在考虑滑动位移的情况下:
1 回收所有屏幕不可见的子View
2 layout所有可见的子View
在这一节,我们先看一下它的简单版本,不考虑滑动位移,不考虑滑动方向等,只考虑初始化时,从头至尾,layout所有可见的子View,在下一节我会配合滑动事件放出它的完整版.
int topOffset = getPaddingTop();//布局时的上偏移
int leftOffset = getPaddingLeft();//布局时的左偏移
int lineMaxHeight = 0;//每一行最大的高度
int minPos = mFirstVisiPos;//初始化时,我们不清楚究竟要layout多少个子View,所以就假设从0~itemcount-1
mLastVisiPos = getItemCount() - 1;
//顺序addChildView
for (int i = minPos; i <= mLastVisiPos; i++) {
//找recycler要一个childItemView,我们不管它是从scrap里取,还是从RecyclerViewPool里取,亦或是onCreateViewHolder里拿。
View child = recycler.getViewForPosition(i);
addView(child);
measureChildWithMargins(child, 0, 0);
//计算宽度 包括margin
if (leftOffset + getDecoratedMeasurementHorizontal(child) <= getHorizontalSpace()) {//当前行还排列的下
layoutDecoratedWithMargins(child, leftOffset, topOffset, leftOffset + getDecoratedMeasurementHorizontal(child), topOffset + getDecoratedMeasurementVertical(child));
//改变 left lineHeight
leftOffset += getDecoratedMeasurementHorizontal(child);
lineMaxHeight = Math.max(lineMaxHeight, getDecoratedMeasurementVertical(child));
} else {//当前行排列不下
//改变top left lineHeight
leftOffset = getPaddingLeft();
topOffset += lineMaxHeight;
lineMaxHeight = 0;
//新起一行的时候要判断一下边界
if (topOffset - dy > getHeight() - getPaddingBottom()) {
//越界了 就回收
removeAndRecycleView(child, recycler);
mLastVisiPos = i - 1;
} else {
layoutDecoratedWithMargins(child, leftOffset, topOffset, leftOffset + getDecoratedMeasurementHorizontal(child), topOffset + getDecoratedMeasurementVertical(child));
//改变 left lineHeight
leftOffset += getDecoratedMeasurementHorizontal(child);
lineMaxHeight = Math.max(lineMaxHeight, getDecoratedMeasurementVertical(child));
}
}
}
用到的一些工具函数(在系列开篇已介绍过):
//模仿LLM Horizontal 源码
/**
-
获取某个childView在水平方向所占的空间
-
@param view
-
@return
*/
public int getDecoratedMeasurementHorizontal(View view) {
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
view.getLayoutParams();
return getDecoratedMeasuredWidth(view) + params.leftMargin
- params.rightMargin;
}
/**
-
获取某个childView在竖直方向所占的空间
-
@param view
-
@return
*/
public int getDecoratedMeasurementVertical(View view) {
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
view.getLayoutParams();
return getDecoratedMeasuredHeight(view) + params.topMargin
- params.bottomMargin;
}
public int getVerticalSpace() {
return getHeight() - getPaddingTop() - getPaddingBottom();
}
public int getHorizontalSpace() {
return getWidth() - getPaddingLeft() - getPaddingRight();
}
如上编写一个超级简单的fill()
方法,运行,你的程序应该就能看到流式布局的效果出现了。
可是千万别开心,因为痛苦的计算远没到来。
如果这些都看不懂,那么我建议:
一,直接下载完整代码,配合后面的章节看,看到后面也许前面的就好理解了= =。
二,去学习一下自定义ViewGroup的知识。
此时虽然界面上已经展示了流式布局的效果,可是它并不能滑动,下一节我们让它动起来。
四,动起来