ExtendableListView.java
1, 因为是首次layout, changed为true, childCount是 0,
//ExtendableListView.java /** * {@inheritDoc} */ @Override protected void onLayout(final boolean changed, final int l, final int t, final int r, final int b) { // super.onLayout(changed, l, t, r, b); - skipping base AbsListView implementation on purpose // haven't set an adapter yet? get to it if (mAdapter == null) { return; } if (changed) { int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { getChildAt(i).forceLayout(); } mRecycleBin.markChildrenDirty(); } // TODO get the height of the view?? mInLayout = true; layoutChildren(); mInLayout = false; }
2, layoutChildren, 在步骤1中可知 在layoutChildren()期间 变量mInLayout 一直为true。
在attachToWindow() 和 setAdapter(..)时 ,如果adapter不为null, 则mDataChanged 设置为 true, 所以假设这里的mDataChanged是true .
在handleDataChanged() 中, mLayoutMode 被设置为 LAYOUT_FORTCE_TOP , 所以 mFirstPosition 为 0, 然后执行 fillFromTop( top) ,假设没有headerview, 那么 top值是0 或者 listview的 topPadding值。
//ExtendableListView.java /** * {@inheritDoc} */ @Override protected void layoutChildren() { if (mBlockLayoutRequests) return; mBlockLayoutRequests = true; try { super.layoutChildren(); invalidate(); ... int childrenTop = getListPaddingTop(); int childCount = getChildCount(); View oldFirst = null; // our last state so we keep our position if (mLayoutMode == LAYOUT_NORMAL) { oldFirst = getChildAt(0); } boolean dataChanged = mDataChanged; if (dataChanged) { handleDataChanged(); } ... // Pull all children into the RecycleBin. // These views will be reused if possible final int firstPosition = mFirstPosition; final RecycleBin recycleBin = mRecycleBin; if (dataChanged) { // true now for (int i = 0; i < childCount; i++) { // childcount is 0 now recycleBin.addScrapView(getChildAt(i), firstPosition + i); } } else { recycleBin.fillActiveViews(childCount, firstPosition); } // Clear out old views detachAllViewsFromParent(); recycleBin.removeSkippedScrap(); switch (mLayoutMode) { case LAYOUT_FORCE_TOP: { mFirstPosition = 0; resetToTop(); adjustViewsUpOrDown(); fillFromTop(childrenTop); adjustViewsUpOrDown(); break; } case LAYOUT_SYNC: { fillSpecific(mSyncPosition, mSpecificTop); break; } case LAYOUT_NORMAL: default: { if (childCount == 0) { fillFromTop(childrenTop); } else if (mFirstPosition < mItemCount) { fillSpecific(mFirstPosition, oldFirst == null ? childrenTop : oldFirst.getTop()); } else { fillSpecific(0, childrenTop); } break; } } // Flush any cached views that did not get reused above recycleBin.scrapActiveViews(); mDataChanged = false; mNeedSync = false; mLayoutMode = LAYOUT_NORMAL; invokeOnItemScrollListener(); } finally { mBlockLayoutRequests = false; } } ////////////////////////////////////////////////////////
2' , override:
这里将mColumnBottoms[] 和 mColumnTops[]是一样的值(每个值都是0, 或者listview的 topPadding值), 因为还没任何child view
//StaggeredGridView.java @Override protected void layoutChildren() { preLayoutChildren(); super.layoutChildren(); } //mNeedSync 在 onRestoreInstanceState 时才会被设置为true,其他情况均为false private void preLayoutChildren() { // on a major re-layout reset for our next layout pass if (!mNeedSync) { Arrays.fill(mColumnBottoms, 0); } else { mNeedSync = false; } // copy the tops into the bottom // since we're going to redo a layout pass that will draw down from // the top System.arraycopy(mColumnTops, 0, mColumnBottoms, 0, mColumnCount); }
3, 回顾2, ExtendableListView.java, fillFromTop, 其参数是0 或者 listView的 topPadding值;mFirstPosition是0
在fillDown中, 此时 itemPos 是0 ; nextTop是顶部位置: topPadding 或 0 , 通过while循环这一过程,将有足够多的child view 被生成以填满整个listview。
//ExtendableListView.java /** * Fills the list from top to bottom, starting with mFirstPosition */ private View fillFromTop(int nextTop) { mFirstPosition = Math.min(mFirstPosition, mItemCount - 1); if (mFirstPosition < 0) { mFirstPosition = 0; } return fillDown(mFirstPosition, nextTop); } private View fillDown(int itemPos, int nextTop) { //(0,topPadding) if (DBG) Log.d(TAG, "fillDown - pos:" + pos + " nextTop:" + nextTop); View selectedView = null; int end = getHeight(); if (mClipToPadding) { end -= getListPaddingBottom(); } while ((nextTop < end || hasSpaceDown()) && pos < mItemCount) { // TODO : add selection support // 目前不支持select , 所以selected一律为false makeAndAddView(itemPos, nextTop, true, false); itemPos++; nextTop = getNextChildDownsTop(itemPos); // = child.getBottom(); } return selectedView; }
4, makeAndAddView(0, 0, true, false):
执行obtainView
//ExtendableListView.java /** * Gets a view either a new view an unused view?? or a recycled view and adds it to our children */ private View makeAndAddView(int position, int y, boolean flowDown, boolean selected) { View child; onChildCreated(position, flowDown); if (!mDataChanged) {// now mDataChanged is true , so it is skipped here // Try to use an existing view for this position child = mRecycleBin.getActiveView(position); if (child != null) { // Found it -- we're using an existing child // This just needs to be positioned setupChild(child, position, y, flowDown, selected, true); return child; } } // Make a new view for this position, or convert an unused view if possible child = obtainView(position, mIsScrap); // This needs to be positioned and measured setupChild(child, position, y, flowDown, selected, mIsScrap[0]); return child; }
4.1 onChildCreated( 0, true): ExtendableListView 的实现为空, 所以直接看StaggeredGridView的实现:
执行if 部分,需要看 getChildColumn 和 setPositionColumn 。
//StaggeredGridView.java @Override protected void onChildCreated(final int position, final boolean flowDown) { super.onChildCreated(position, flowDown); if (!isHeaderOrFooter(position)) { // do we already have a column for this position? final int column = getChildColumn(position, flowDown); setPositionColumn(position, column); } else { setPositionIsHeaderFooter(position); } }