StaggeredGridView 實現分析--首次填充過程(一)續

4.2 getChildColumn 和 setPositionColumn :
java

mPostionData 是一個SparseArray , 記錄了每一個 item 對應的 GridItemRecord對象,app

//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' setPositionColumnide

  //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:this


5, setupChild (child, 0, topPadding , true, false, false):spa

執行 addViewToParent, code

needToMeasure 爲 true;mMotionPostion 爲 0orm

而後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 .element

GridLayoutParams 多了一個column變量, 記錄該child所屬的列,onMeasureChild 將寬度限定爲mColumnWidth , 並記錄了heightRatioget

@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怎樣出現。

相關文章
相關標籤/搜索