@Override protected void onSizeChanged(int w, int h) { super.onSizeChanged(w, h); boolean isLandscape = isLandscape(); int newColumnCount = isLandscape ? mColumnCountLandscape : mColumnCountPortrait; if (mColumnCount != newColumnCount) { mColumnCount = newColumnCount; mColumnWidth = calculateColumnWidth(w); mColumnTops = new int[mColumnCount]; mColumnBottoms = new int[mColumnCount]; mColumnLefts = new int[mColumnCount]; mDistanceToTop = 0; // rebuild the columns initColumnTopsAndBottoms(); initColumnLefts(); // if we have data if (getCount() > 0 && mPositionData.size() > 0) { onColumnSync(); } requestLayout(); } }
private void offsetGridHeaderFooter( final View child, final int position, final boolean flowDown, final int childrenLeft, final int childTop) { // offset the top and bottom of all our columns // if it's the footer we want it below the lowest child bottom int gridChildTop; int gridChildBottom; if (flowDown) { gridChildTop = getLowestPositionedBottom(); gridChildBottom = gridChildTop + getChildHeight(child); } else { gridChildBottom = getHighestPositionedTop(); gridChildTop = gridChildBottom - getChildHeight(child); } for (int i = 0; i < mColumnCount; i++) { updateColumnTopIfNeeded(i, gridChildTop); updateColumnBottomIfNeeded(i, gridChildBottom); } super.onOffsetChild(child, position, flowDown, childrenLeft, gridChildTop); }
@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) { // for headers and weird ignored views super.onMeasureChild(child, layoutParams); } else { if (DBG) Log.d(TAG, "onMeasureChild BEFORE position:" + position + " h:" + getMeasuredHeight()); // 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); if (DBG) Log.d(TAG, "onMeasureChild AFTER position:" + position + " h:" + childHeight); }
@Override protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); if (mColumnCount <= 0) { boolean isLandscape = isLandscape(); mColumnCount = isLandscape ? mColumnCountLandscape : mColumnCountPortrait; } // our column width is the width of the listview // minus it's padding // minus the total items margin // divided by the number of columns mColumnWidth = calculateColumnWidth(getMeasuredWidth()); if (mColumnTops == null || mColumnTops.length != mColumnCount) { mColumnTops = new int[mColumnCount]; initColumnTops(); } if (mColumnBottoms == null || mColumnBottoms.length != mColumnCount) { mColumnBottoms = new int[mColumnCount]; initColumnBottoms(); } if (mColumnLefts == null || mColumnLefts.length != mColumnCount) { mColumnLefts = new int[mColumnCount]; initColumnLefts(); } }
@Override protected void adjustViewsAfterFillGap(final boolean down) { super.adjustViewsAfterFillGap(down); // fix vertical gaps when hitting the top after a rotate // only when scrolling back up! if (!down) { alignTops(); } }
@SuppressWarnings("unchecked") @Override public void onRestoreInstanceState(Parcelable state) { GridListSavedState ss = (GridListSavedState) state; mColumnCount = ss.columnCount; mColumnTops = ss.columnTops; mColumnBottoms = new int[mColumnCount]; mPositionData = ss.positionData; mNeedSync = true; super.onRestoreInstanceState(ss); }
@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); if (DBG) Log.d(TAG, "onChildCreated position:" + position + " is in column:" + column); } else { setPositionIsHeaderFooter(position); } }
private void offsetGridChild( final View child, final int position, final boolean flowDown, final int childrenLeft, final int childTop) { // stash the bottom and the top if it's higher positioned int column = getPositionColumn(position); int gridChildTop; int gridChildBottom; int childTopMargin = getChildTopMargin(position); int childBottomMargin = getChildBottomMargin(); int verticalMargins = childTopMargin + childBottomMargin; if (flowDown) { gridChildTop = mColumnBottoms[column]; // the next items top is the // last items bottom gridChildBottom = gridChildTop + (getChildHeight(child) + verticalMargins); } else { gridChildBottom = mColumnTops[column]; // the bottom of the next // column up is our top gridChildTop = gridChildBottom - (getChildHeight(child) + verticalMargins); } if (DBG) Log.d( TAG, "onOffsetChild position:" + position + " column:" + column + " childTop:" + childTop + " gridChildTop:" + gridChildTop + " gridChildBottom:" + gridChildBottom); // we also know the column of this view so let's stash it in the // view's layout params GridLayoutParams layoutParams = (GridLayoutParams) child.getLayoutParams(); layoutParams.column = column; updateColumnBottomIfNeeded(column, gridChildBottom); updateColumnTopIfNeeded(column, gridChildTop); super.onOffsetChild(child, position, flowDown, childrenLeft, gridChildTop + childTopMargin); }
@Override protected void onChildrenDetached(final int start, final int count) { super.onChildrenDetached(start, count); // go through our remaining views and sync the top and bottom stash. // Repair the top and bottom column boundaries from the views we still // have Arrays.fill(mColumnTops, Integer.MAX_VALUE); Arrays.fill(mColumnBottoms, 0); for (int i = 0; i < getChildCount(); i++) { final View child = getChildAt(i); if (child != null) { final LayoutParams childParams = (LayoutParams) child.getLayoutParams(); if (childParams.viewType != ITEM_VIEW_TYPE_HEADER_OR_FOOTER && childParams instanceof GridLayoutParams) { GridLayoutParams layoutParams = (GridLayoutParams) childParams; int column = layoutParams.column; int position = layoutParams.position; final int childTop = child.getTop(); if (childTop < mColumnTops[column]) { mColumnTops[column] = childTop - getChildTopMargin(position); } final int childBottom = child.getBottom(); if (childBottom > mColumnBottoms[column]) { mColumnBottoms[column] = childBottom + getChildBottomMargin(); } } else { // the header and footer here final int childTop = child.getTop(); final int childBottom = child.getBottom(); for (int col = 0; col < mColumnCount; col++) { if (childTop < mColumnTops[col]) { mColumnTops[col] = childTop; } if (childBottom > mColumnBottoms[col]) { mColumnBottoms[col] = childBottom; } } } } } }
@Override protected void onSizeChanged(final int w, final int h, final int oldw, final int oldh) { super.onSizeChanged(w, h, oldw, oldh); onSizeChanged(w, h); }
@Override protected void offsetChildrenTopAndBottom(final int offset) { super.offsetChildrenTopAndBottom(offset); offsetAllColumnsTopAndBottom(offset); offsetDistanceToTop(offset); }
@Override protected void layoutChildren() { preLayoutChildren(); super.layoutChildren(); }