4.2 getChildColumn 和 setPositionColumn :
mPostionData 是一个SparseArray , 记录了每个 item 对应的 GridItemRecord对象,
//StaggeredGridView.java
private int getChildColumn(final int itemPos, final boolean flowDown) {// (0, true)
// do we already have a column for this child position?
int column = getPositionColumn(itemPos); // returned -1 for the current case
// we don't have the column or it no longer fits in our grid
final int columnCount = mColumnCount;
if (column < 0 || column >= columnCount) {
// if we're going down -
// get the highest positioned (lowest value)
// column bottom
if (flowDown) {
column = getHighestPositionedBottomColumn(); // so we got here , and returned 0 for the current case
}
else {
column = getLowestPositionedTopColumn();
}
}
return column;
}
private int getPositionColumn(final int itemPos) {
GridItemRecord rec = mPositionData.get(position, null);
return rec != null ? rec.column : -1;
}
private int getHighestPositionedBottomColumn() {
int columnFound = 0;
int highestPositionedBottom = Integer.MAX_VALUE;
// the highest positioned bottom is the one with the lowest value :D
for (int i = 0; i < mColumnCount; i++) {
int bottom = mColumnBottoms[i];
if (bottom < highestPositionedBottom) {
highestPositionedBottom = bottom;
columnFound = i;
}
}
return columnFound;
}
4.2' setPositionColumn
//StaggeredGridView.java
private void setPositionColumn(final int position, final int column) {// (0, 0)
GridItemRecord rec = getOrCreateRecord(position);
rec.column = column; // colunm is set to 0, now mPostionData has one element :D
}
private GridItemRecord getOrCreateRecord(final int position) {//(0)
GridItemRecord rec = mPositionData.get(position, null); //mPositionData is empty now , so null returned
if (rec == null) {
rec = new GridItemRecord(); // create one
mPositionData.append(position, rec);
}
return rec;
}
然后返回到4.1 --> 4 , 新的view 被创建(child) , 然后setupChild ---> 步骤5:
5, setupChild (child, 0, topPadding , true, false, false):
执行 addViewToParent,
needToMeasure 为 true;mMotionPostion 为 0
然后measure , layout, 此时 listview已经有了一个 child. :D
//ExtendableListView.java
private void setupChild(View child, int itemPos, int y, boolean flowDown,
boolean selected, boolean recycled) {
final boolean isSelected = false; // TODO : selected && shouldShowSelector();
final boolean updateChildSelected = isSelected != child.isSelected();// false
final int mode = mTouchMode;
final boolean isPressed = mode > TOUCH_MODE_DOWN && mode < TOUCH_MODE_SCROLLING &&
mMotionPosition == itemPos; // 0 now
final boolean updateChildPressed = isPressed != child.isPressed();
final boolean needToMeasure = !recycled || updateChildSelected || child.isLayoutRequested(); //true
int itemViewType = mAdapter.getItemViewType(itemPos);
LayoutParams layoutParams;
if (itemViewType == ITEM_VIEW_TYPE_HEADER_OR_FOOTER) {
layoutParams = generateWrapperLayoutParams(child);
}
else {
layoutParams = generateChildLayoutParams(child);
}
layoutParams.viewType = itemViewType;
layoutParams.position = position;
if (recycled || (layoutParams.recycledHeaderFooter &&
layoutParams.viewType == AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER)) {
attachViewToParent(child, flowDown ? -1 : 0, layoutParams);
}
else {
if (layoutParams.viewType == AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER) {
layoutParams.recycledHeaderFooter = true;
}
addViewInLayout(child, flowDown ? -1 : 0, layoutParams, true); //got here , added a view but don't layout it
}
if (updateChildSelected) {
child.setSelected(isSelected);
}
if (updateChildPressed) {
child.setPressed(isPressed);
}
if (needToMeasure) {
onMeasureChild(child, layoutParams);
}
else {
cleanupLayoutState(child);
}
final int w = child.getMeasuredWidth();
final int h = child.getMeasuredHeight();
final int childTop = flowDown ? y : y - h;
final int childrenLeft = getChildLeft(itemPos);
if (needToMeasure) {
final int childRight = childrenLeft + w;
final int childBottom = childTop + h;
onLayoutChild(child, itemPos, flowDown, childrenLeft, childTop, childRight, childBottom);
}
else {
onOffsetChild(child, itemPos, flowDown, childrenLeft, childTop);
}
}
上面有几个点: generateChildLayoutParams( child ) , getChildLeft 、onLayoutChild .
GridLayoutParams 多了一个column变量, 记录该child所属的列,onMeasureChild 将宽度限定为mColumnWidth , 并记录了heightRatio
@Override
protected void onMeasureChild(final View child, final LayoutParams layoutParams) {
final int viewType = layoutParams.viewType;
final int position = layoutParams.position;
if (viewType == ITEM_VIEW_TYPE_HEADER_OR_FOOTER ||
viewType == ITEM_VIEW_TYPE_IGNORE) {
super.onMeasureChild(child, layoutParams);
}
else {
// measure it to the width of our column.
int childWidthSpec = MeasureSpec.makeMeasureSpec(mColumnWidth, MeasureSpec.EXACTLY);
int childHeightSpec;
if (layoutParams.height > 0) {
childHeightSpec = MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.EXACTLY);
}
else {
childHeightSpec = MeasureSpec.makeMeasureSpec(LayoutParams.WRAP_CONTENT, MeasureSpec.UNSPECIFIED);
}
child.measure(childWidthSpec, childHeightSpec);
}
final int childHeight = getChildHeight(child);
setPositionHeightRatio(position, childHeight);
}
private void setPositionHeightRatio(final int itemPos, final int height) { //(0 ,childHeight )
GridItemRecord rec = getOrCreateRecord(itemPos);
rec.heightRatio = (double) height / (double) mColumnWidth;
}
getChildLeft: mColumnLefts[] 记录了每一列左侧的开始移位
@Override
protected int getChildLeft(final int position) {
if (isHeaderOrFooter(position)) {
return super.getChildLeft(position);
}
else {
final int column = getPositionColumn(position);
return mColumnLefts[column];
}
}
private int getPositionColumn(final int itemPos) {
GridItemRecord rec = mPositionData.get(itemPos, null);
return rec != null ? rec.column : -1;
}
另外, 在onLayoutChild 中调用了layoutGridChild , 这个方法完成了child的layout过程,并且更新了 mColumnTops[] 、mColumnTops[] 记录。
到此,listview中已经有了第一个child, 然后回到步骤4的结尾, 然后回到步骤3的 while循环中: 此时makeAndAddView已经成功地往listview中加入了第一个view, 接下来要加入第二个、第三个...第X个child, 假设有listview有两列(可以设置,列越多,mColumnWidth就越小),我们记下makeAndView结束时的状态,然后看第二个child view怎样出现。