public override int FillToEnd(int leadingEdge, int markerLine, int anchorPosition, SectionData sd, LayoutState state) { int itemCount = state.recyclerState.ItemCount; for (int i = anchorPosition; i < itemCount; i++) { if (markerLine >= leadingEdge) { break; } LayoutState.View next = state.GetView(i); LayoutManager.LayoutParams lp = next.LayoutParams; if (lp.FirstPosition != sd.firstPosition) { state.CacheView(i, next.view); break; } measureChild(next, sd); markerLine = layoutChild(next, markerLine, LayoutManager.Direction.END, sd, state); AddView(next, i, LayoutManager.Direction.END, state); } return(markerLine); }
private int layoutChild(LayoutState.View child, int markerLine, LayoutManager.Direction direction, SectionData sd, LayoutState state) { int height = mLayoutManager.GetDecoratedMeasuredHeight(child.view); int width = mLayoutManager.GetDecoratedMeasuredWidth(child.view); int left = state.isLTR ? sd.contentStart : sd.contentEnd; int right = left + width; int top; int bottom; if (direction == LayoutManager.Direction.END) { top = markerLine; bottom = top + height; } else { bottom = markerLine; top = bottom - height; } mLayoutManager.LayoutDecorated(child.view, left, top, right, bottom); if (direction == LayoutManager.Direction.END) { markerLine = mLayoutManager.GetDecoratedBottom(child.view); } else { markerLine = mLayoutManager.GetDecoratedTop(child.view); } return(markerLine); }
public override int ComputeHeaderOffset(int firstVisiblePosition, SectionData sd, LayoutState state) { /* * Work from an assumed overlap and add heights from the start until the overlap is zero or * less, or the current position (or max items) is reached. */ int areaAbove = 0; for (int position = sd.firstPosition + 1; areaAbove < sd.headerHeight && position < firstVisiblePosition; position++) { // Look to see if the header overlaps with the displayed area of the mSection. LayoutState.View child = state.GetView(position); measureChild(child, sd); areaAbove += mLayoutManager.GetDecoratedMeasuredHeight(child.view); state.CacheView(position, child.view); } if (areaAbove == sd.headerHeight) { return(0); } else if (areaAbove > sd.headerHeight) { return(1); } else { return(-areaAbove); } }
/// <summary> /// Fill a row. /// </summary> /// <param name="markerLine"> Line indicating the top edge of the row. </param> /// <param name="anchorPosition"> Position of the first view in the row. </param> /// <param name="direction"> Direction of edge to fill towards. </param> /// <param name="measureRowItems"> Measure the row items. </param> /// <param name="sd"> Section data. </param> /// <param name="state"> Layout state. </param> /// <returns> The height of the new row. </returns> public int fillRow(int markerLine, int anchorPosition, LayoutManager.Direction direction, bool measureRowItems, SectionData sd, LayoutState state) { int rowHeight = 0; LayoutState.View[] views = new LayoutState.View[mNumColumns]; for (int i = 0; i < mNumColumns; i++) { int position = anchorPosition + i; if (position >= state.recyclerState.ItemCount) { break; } LayoutState.View view = state.GetView(position); if (view.LayoutParams.FirstPosition != sd.firstPosition) { state.CacheView(position, view.view); break; } if (measureRowItems) { MeasureChild(view, sd); } else { state.DecacheView(i + anchorPosition); } rowHeight = Math.Max(rowHeight, mLayoutManager.GetDecoratedMeasuredHeight(view.view)); views[i] = view; } bool directionIsStart = direction == LayoutManager.Direction.START; if (directionIsStart) { markerLine -= rowHeight; } for (int i = 0; i < mNumColumns; i++) { int col = directionIsStart ? mNumColumns - i - 1 : i; if (views[col] == null) { continue; } LayoutChild(views[col], markerLine, col, rowHeight, sd, state); AddView(views[col], col + anchorPosition, direction, state); } return(rowHeight); }
protected int AddView(LayoutState.View child, int position, LayoutManager.Direction direction, LayoutState state) { int addIndex; if (direction == LayoutManager.Direction.START) { addIndex = 0; } else { addIndex = mLayoutManager.ChildCount; } state.DecacheView(position); mLayoutManager.AddView(child.view, addIndex); return(addIndex); }
/// <summary> /// Layout out a view for the given column in a row. Views that have a height param of /// MATCH_PARENT are fixed to the height of the row. /// </summary> /// <param name="child"> View to lay out. </param> /// <param name="top"> Line indicating the top edge of the row. </param> /// <param name="col"> Column view is being placed into. </param> /// <param name="rowHeight"> Height of the row. </param> /// <param name="sd"> Section data. </param> /// <param name="state"> Layout state. </param> private void LayoutChild(LayoutState.View child, int top, int col, int rowHeight, SectionData sd, LayoutState state) { int height; if (child.LayoutParams.Height == LayoutManager.LayoutParams.MatchParent) { height = rowHeight; } else { height = mLayoutManager.GetDecoratedMeasuredHeight(child.view); } int width = mLayoutManager.GetDecoratedMeasuredWidth(child.view); col = AdjustColumnForLayoutDirection(col, state.isLTR); int bottom = top + height; int left = (state.isLTR ? sd.contentStart : sd.contentEnd) + col * mColumnWidth; int right = left + width; mLayoutManager.LayoutDecorated(child.view, left, top, right, bottom); }
public override int FillToStart(int leadingEdge, int markerLine, int anchorPosition, SectionData sd, LayoutState state) { // Check to see if we have to adjust for minimum section height. We don't if there is an // attached non-header view in this section. bool applyMinHeight = false; for (int i = 0; i < state.recyclerState.ItemCount; i++) { View check = mLayoutManager.GetChildAt(0); if (check == null) { applyMinHeight = false; break; } LayoutManager.LayoutParams checkParams = (LayoutManager.LayoutParams)check.LayoutParameters; if (checkParams.FirstPosition != sd.firstPosition) { applyMinHeight = true; break; } if (!checkParams.isHeader) { applyMinHeight = false; break; } } // Work out offset to marker line by measuring items from the end. If section height is less // than min height, then adjust marker line and then lay out items. int measuredPositionsMarker = -1; int sectionHeight = 0; int minHeightOffset = 0; if (applyMinHeight) { for (int i = anchorPosition; i >= 0; i--) { LayoutState.View measure = state.GetView(i); state.CacheView(i, measure.view); LayoutManager.LayoutParams lp = measure.LayoutParams; if (lp.FirstPosition != sd.firstPosition) { break; } if (lp.isHeader) { continue; } measureChild(measure, sd); sectionHeight += mLayoutManager.GetDecoratedMeasuredHeight(measure.view); measuredPositionsMarker = i; if (sectionHeight >= sd.minimumHeight) { break; } } if (sectionHeight < sd.minimumHeight) { minHeightOffset = sectionHeight - sd.minimumHeight; markerLine += minHeightOffset; } } for (int i = anchorPosition; i >= 0; i--) { if (markerLine - minHeightOffset < leadingEdge) { break; } LayoutState.View next = state.GetView(i); LayoutManager.LayoutParams lp = next.LayoutParams; if (lp.isHeader) { state.CacheView(i, next.view); break; } if (lp.FirstPosition != sd.firstPosition) { state.CacheView(i, next.view); break; } if (!applyMinHeight || i < measuredPositionsMarker) { measureChild(next, sd); } else { state.DecacheView(i); } markerLine = layoutChild(next, markerLine, LayoutManager.Direction.START, sd, state); AddView(next, i, LayoutManager.Direction.START, state); } return(markerLine); }
private void measureChild(LayoutState.View child, SectionData sd) { mLayoutManager.MeasureChildWithMargins(child.view, sd.TotalMarginWidth, 0); }
public override int FillToEnd(int leadingEdge, int markerLine, int anchorPosition, SectionData sd, LayoutState state) { if (markerLine >= leadingEdge) { return(markerLine); } int itemCount = state.recyclerState.ItemCount; if (anchorPosition >= itemCount) { return(markerLine); } LayoutState.View anchor = state.GetView(anchorPosition); state.CacheView(anchorPosition, anchor.view); if (anchor.LayoutParams.FirstPosition != sd.firstPosition) { return(markerLine); } int firstContentPosition = sd.hasHeader ? sd.firstPosition + 1 : sd.firstPosition; // Ensure the anchor is the first item in the row. int col = (anchorPosition - firstContentPosition) % mNumColumns; for (int i = 1; i <= col; i++) { // Detach and scrap attached items in this row, so we can re-lay them again. The last // child view in the index can be the header so we just skip past it if it last. for (int j = 1; j <= mLayoutManager.ChildCount; j++) { View child = mLayoutManager.GetChildAt(mLayoutManager.ChildCount - j); if (mLayoutManager.GetPosition(child) == anchorPosition - i) { markerLine = mLayoutManager.GetDecoratedTop(child); mLayoutManager.DetachAndScrapViewAt(j, state.recycler); break; } LayoutManager.LayoutParams lp = (LayoutManager.LayoutParams)child.LayoutParameters; if (lp.FirstPosition != sd.firstPosition) { break; } } } anchorPosition = anchorPosition - col; // Lay out rows to end. for (int i = anchorPosition; i < itemCount; i += mNumColumns) { if (markerLine >= leadingEdge) { break; } LayoutState.View view = state.GetView(i); if (view.LayoutParams.FirstPosition != sd.firstPosition) { state.CacheView(i, view.view); break; } int rowHeight = fillRow(markerLine, i, LayoutManager.Direction.END, true, sd, state); markerLine += rowHeight; } return(markerLine); }
/// <summary> /// Measure view. A view is given an area as wide as a single column with an undefined height. /// </summary> /// <param name="child"> View to measure. </param> /// <param name="sd"> Section data. </param> private void MeasureChild(LayoutState.View child, SectionData sd) { int widthOtherColumns = (mNumColumns - 1) * mColumnWidth; mLayoutManager.MeasureChildWithMargins(child.view, sd.marginStart + sd.marginEnd + widthOtherColumns, 0); }
public override int FillToStart(int leadingEdge, int markerLine, int anchorPosition, SectionData sd, LayoutState state) { int firstContentPosition = sd.hasHeader ? sd.firstPosition + 1 : sd.firstPosition; // Check to see if we have to adjust for minimum section height. We don't if there is an // attached non-header view in this section. bool applyMinHeight = false; for (int i = 0; i < mLayoutManager.ChildCount; i++) { View check = mLayoutManager.GetChildAt(0); LayoutManager.LayoutParams checkParams = (LayoutManager.LayoutParams)check.LayoutParameters; if (checkParams.FirstPosition != sd.firstPosition) { applyMinHeight = true; break; } if (!checkParams.isHeader) { applyMinHeight = false; break; } } // _ _ ^ a b int col = (anchorPosition - firstContentPosition) % mNumColumns; for (int i = 1; i < mNumColumns - col; i++) { // Detach and scrap attached items in this row, so we can re-lay them again. The last // child view in the index can be the header so we just skip past it if it last. for (int j = 0; j < mLayoutManager.ChildCount; j++) { View child = mLayoutManager.GetChildAt(j); LayoutManager.LayoutParams lp = (LayoutManager.LayoutParams)child.LayoutParameters; if (lp.FirstPosition != sd.firstPosition) { break; } if (mLayoutManager.GetPosition(child) == anchorPosition + i) { mLayoutManager.DetachAndScrapViewAt(j, state.recycler); break; } } } // Ensure the anchor is the first item in the row. int columnAnchorPosition = anchorPosition - col; // Work out offset to marker line by measuring rows from the end. If section height is less // than min height, then adjust marker line and then lay out items. int measuredPositionsMarker = -1; int sectionHeight = 0; int minHeightOffset = 0; if (applyMinHeight) { for (int i = columnAnchorPosition; i >= 0; i -= mNumColumns) { LayoutState.View check = state.GetView(i); state.CacheView(i, check.view); LayoutManager.LayoutParams checkParams = check.LayoutParams; if (checkParams.FirstPosition != sd.firstPosition) { break; } int rowHeight = 0; for (int j = 0; j < mNumColumns && i + j <= anchorPosition; j++) { LayoutState.View measure = state.GetView(i + j); state.CacheView(i + j, measure.view); LayoutManager.LayoutParams measureParams = measure.LayoutParams; if (measureParams.FirstPosition != sd.firstPosition) { break; } if (measureParams.isHeader) { continue; } MeasureChild(measure, sd); rowHeight = Math.Max(rowHeight, mLayoutManager.GetDecoratedMeasuredHeight(measure.view)); } sectionHeight += rowHeight; measuredPositionsMarker = i; if (sectionHeight >= sd.minimumHeight) { break; } } if (sectionHeight < sd.minimumHeight) { minHeightOffset = sectionHeight - sd.minimumHeight; markerLine += minHeightOffset; } } // Lay out rows to end. for (int i = columnAnchorPosition; i >= 0; i -= mNumColumns) { if (markerLine - minHeightOffset < leadingEdge) { break; } LayoutState.View rowAnchor = state.GetView(i); state.CacheView(i, rowAnchor.view); LayoutManager.LayoutParams lp = rowAnchor.LayoutParams; if (lp.isHeader || lp.FirstPosition != sd.firstPosition) { break; } bool measureRowItems = !applyMinHeight || i < measuredPositionsMarker; int rowHeight = fillRow(markerLine, i, LayoutManager.Direction.START, measureRowItems, sd, state); markerLine -= rowHeight; } return(markerLine); }