ExtendableListView.java
java
1, 由於是首次layout, changed爲true, childCount是 0, ide
//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。this
在attachToWindow() 和 setAdapter(..)時 ,若是adapter不爲null, 則mDataChanged 設置爲 true, 因此假設這裏的mDataChanged是true .spa
在handleDataChanged() 中, mLayoutMode 被設置爲 LAYOUT_FORTCE_TOP , 因此 mFirstPosition 爲 0, 而後執行 fillFromTop( top) ,假設沒有headerview, 那麼 top值是0 或者 listview的 topPadding值。code
//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:ip
這裏將mColumnBottoms[] 和 mColumnTops[]是同樣的值(每一個值都是0, 或者listview的 topPadding值), 由於還沒任何child viewci
//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是0rem
在fillDown中, 此時 itemPos 是0 ; nextTop是頂部位置: topPadding 或 0 , 經過while循環這一過程,將有足夠多的child view 被生成以填滿整個listview。get
//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):
it
執行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); } }