layoutChildSequence method
Primary work horse of performLayout.
Subclasses must implement this method to layout the children of the viewport. The TwoDimensionalViewportParentData.layoutOffset must be set during this method in order for the children to be positioned during paint. Further, children of the viewport must be laid out with the expectation that the parent (this viewport) will use their size.
child.layout(constraints, parentUsesSize: true);
The primary methods used for creating and obtaining children is buildOrObtainChildFor, which takes a ChildVicinity that is used by the TwoDimensionalChildDelegate. If a child is not provided by the delegate for the provided vicinity, the method will return null, otherwise, it will return the RenderBox of the child.
After layoutChildSequence is completed, any remaining children that were not obtained will be disposed.
Implementation
@override
void layoutChildSequence() {
// Reset for a new frame
// We always reset the null terminating indices in case rows or columns have
// been added or removed.
_rowNullTerminatedIndex = null;
_columnNullTerminatedIndex = null;
_mergedVicinities.clear();
_mergedRows.clear();
_mergedColumns.clear();
if (needsDelegateRebuild || didResize) {
// Recomputes the table metrics, invalidates any cached information.
_updateColumnMetrics();
_updateRowMetrics();
_updateScrollBounds();
_debugCheckPinnedExtent();
} else {
// Updates the visible cells based on cached table metrics.
_updateFirstAndLastVisibleCell();
}
final Alignment resolvedAlignment = alignment.resolve(textDirection);
_hAlignmentOffset = 0.0;
if (!_columnsAreInfinite && _columnMetrics.isNotEmpty) {
final double totalWidth =
_pinnedColumnsExtent + _columnMetrics[delegate.columnCount! - 1]!.trailingOffset;
if (totalWidth < viewportDimension.width) {
_hAlignmentOffset =
(viewportDimension.width - totalWidth) * (resolvedAlignment.x + 1.0) / 2.0;
}
}
_vAlignmentOffset = 0.0;
if (!_rowsAreInfinite && _rowMetrics.isNotEmpty) {
final double totalHeight =
_pinnedRowsExtent + _rowMetrics[delegate.rowCount! - 1]!.trailingOffset;
if (totalHeight < viewportDimension.height) {
_vAlignmentOffset =
(viewportDimension.height - totalHeight) * (resolvedAlignment.y + 1.0) / 2.0;
}
}
if (_firstNonPinnedCell == null &&
_lastPinnedRow == null &&
_lastPinnedColumn == null &&
_firstTrailingPinnedRow == null &&
_firstTrailingPinnedColumn == null) {
assert(_lastNonPinnedCell == null);
return;
}
final double trailingPinnedColumnOffset = _firstTrailingPinnedColumn != null
? -(viewportDimension.width - _trailingPinnedColumnsExtent)
: 0.0;
final double trailingPinnedRowOffset = _firstTrailingPinnedRow != null
? -(viewportDimension.height - _trailingPinnedRowsExtent)
: 0.0;
final double? offsetIntoColumn = _firstNonPinnedColumn != null
? horizontalOffset.pixels -
_columnMetrics[_firstNonPinnedColumn]!.leadingOffset -
_leadingPinnedColumnsExtent -
_hAlignmentOffset
: null;
final double? offsetIntoRow = _firstNonPinnedRow != null
? verticalOffset.pixels -
_rowMetrics[_firstNonPinnedRow]!.leadingOffset -
_leadingPinnedRowsExtent -
_vAlignmentOffset
: null;
// Row Category L (Leading Pinned)
if (_lastPinnedRow != null) {
// (L, L)
if (_lastPinnedColumn != null) {
_layoutCells(
start: TableVicinity.zero,
end: TableVicinity(column: _lastPinnedColumn!, row: _lastPinnedRow!),
offset: Offset(-_hAlignmentOffset, -_vAlignmentOffset),
);
}
// (L, N)
if (_firstNonPinnedColumn != null) {
assert(_lastNonPinnedColumn != null);
assert(offsetIntoColumn != null);
_layoutCells(
start: TableVicinity(column: _firstNonPinnedColumn!, row: 0),
end: TableVicinity(column: _lastNonPinnedColumn!, row: _lastPinnedRow!),
offset: Offset(offsetIntoColumn!, -_vAlignmentOffset),
);
}
// (L, T)
if (_firstTrailingPinnedColumn != null) {
_layoutCells(
start: TableVicinity(column: _firstTrailingPinnedColumn!, row: 0),
end: TableVicinity(column: delegate.columnCount! - 1, row: _lastPinnedRow!),
offset: Offset(trailingPinnedColumnOffset, -_vAlignmentOffset),
);
}
}
// Row Category N (Non-Pinned)
if (_firstNonPinnedRow != null) {
assert(_lastNonPinnedRow != null);
assert(offsetIntoRow != null);
// (N, L)
if (_lastPinnedColumn != null) {
_layoutCells(
start: TableVicinity(column: 0, row: _firstNonPinnedRow!),
end: TableVicinity(column: _lastPinnedColumn!, row: _lastNonPinnedRow!),
offset: Offset(-_hAlignmentOffset, offsetIntoRow!),
);
}
// (N, N)
if (_firstNonPinnedColumn != null) {
assert(_lastNonPinnedColumn != null);
assert(offsetIntoColumn != null);
_layoutCells(
start: TableVicinity(column: _firstNonPinnedColumn!, row: _firstNonPinnedRow!),
end: TableVicinity(column: _lastNonPinnedColumn!, row: _lastNonPinnedRow!),
offset: Offset(offsetIntoColumn!, offsetIntoRow!),
);
}
// (N, T)
if (_firstTrailingPinnedColumn != null) {
_layoutCells(
start: TableVicinity(column: _firstTrailingPinnedColumn!, row: _firstNonPinnedRow!),
end: TableVicinity(column: delegate.columnCount! - 1, row: _lastNonPinnedRow!),
offset: Offset(trailingPinnedColumnOffset, offsetIntoRow!),
);
}
}
// Row Category T (Trailing Pinned)
if (_firstTrailingPinnedRow != null) {
// (T, L)
if (_lastPinnedColumn != null) {
_layoutCells(
start: TableVicinity(column: 0, row: _firstTrailingPinnedRow!),
end: TableVicinity(column: _lastPinnedColumn!, row: delegate.rowCount! - 1),
offset: Offset(-_hAlignmentOffset, trailingPinnedRowOffset),
);
}
// (T, N)
if (_firstNonPinnedColumn != null) {
assert(_lastNonPinnedColumn != null);
assert(offsetIntoColumn != null);
_layoutCells(
start: TableVicinity(column: _firstNonPinnedColumn!, row: _firstTrailingPinnedRow!),
end: TableVicinity(column: _lastNonPinnedColumn!, row: delegate.rowCount! - 1),
offset: Offset(offsetIntoColumn!, trailingPinnedRowOffset),
);
}
// (T, T)
if (_firstTrailingPinnedColumn != null) {
_layoutCells(
start: TableVicinity(column: _firstTrailingPinnedColumn!, row: _firstTrailingPinnedRow!),
end: TableVicinity(column: delegate.columnCount! - 1, row: delegate.rowCount! - 1),
offset: Offset(trailingPinnedColumnOffset, trailingPinnedRowOffset),
);
}
}
}