@@ -116,6 +116,7 @@ class TableView extends TwoDimensionalScrollView {
116116 super .dragStartBehavior,
117117 super .keyboardDismissBehavior,
118118 super .clipBehavior,
119+ this .alignment = Alignment .topLeft,
119120 });
120121
121122 /// Creates a [TableView] of widgets that are created on demand.
@@ -155,6 +156,7 @@ class TableView extends TwoDimensionalScrollView {
155156 required TableSpanBuilder columnBuilder,
156157 required TableSpanBuilder rowBuilder,
157158 required TableViewCellBuilder cellBuilder,
159+ this .alignment = Alignment .topLeft,
158160 }) : assert (pinnedRowCount >= 0 ),
159161 assert (rowCount == null || rowCount >= 0 ),
160162 assert (rowCount == null || rowCount >= pinnedRowCount),
@@ -199,6 +201,7 @@ class TableView extends TwoDimensionalScrollView {
199201 required TableSpanBuilder columnBuilder,
200202 required TableSpanBuilder rowBuilder,
201203 List <List <TableViewCell >> cells = const < List <TableViewCell >> [],
204+ this .alignment = Alignment .topLeft,
202205 }) : assert (pinnedRowCount >= 0 ),
203206 assert (pinnedColumnCount >= 0 ),
204207 super (
@@ -211,6 +214,11 @@ class TableView extends TwoDimensionalScrollView {
211214 ),
212215 );
213216
217+ /// The alignment of the table within the viewport when there is extra space.
218+ ///
219+ /// Defaults to [Alignment.topLeft] .
220+ final AlignmentGeometry alignment;
221+
214222 @override
215223 TableViewport buildViewport (
216224 BuildContext context,
@@ -226,6 +234,7 @@ class TableView extends TwoDimensionalScrollView {
226234 mainAxis: mainAxis,
227235 cacheExtent: cacheExtent,
228236 clipBehavior: clipBehavior,
237+ alignment: alignment,
229238 );
230239 }
231240}
@@ -245,8 +254,12 @@ class TableViewport extends TwoDimensionalViewport {
245254 required super .mainAxis,
246255 super .cacheExtent,
247256 super .clipBehavior,
257+ this .alignment = Alignment .topLeft,
248258 });
249259
260+ /// The alignment of the table within the viewport when there is extra space.
261+ final AlignmentGeometry alignment;
262+
250263 @override
251264 RenderTwoDimensionalViewport createRenderObject (BuildContext context) {
252265 return RenderTableViewport (
@@ -259,6 +272,8 @@ class TableViewport extends TwoDimensionalViewport {
259272 clipBehavior: clipBehavior,
260273 delegate: delegate as TableCellDelegateMixin ,
261274 childManager: context as TwoDimensionalChildManager ,
275+ alignment: alignment,
276+ textDirection: Directionality .maybeOf (context),
262277 );
263278 }
264279
@@ -275,7 +290,9 @@ class TableViewport extends TwoDimensionalViewport {
275290 ..mainAxis = mainAxis
276291 ..cacheExtent = cacheExtent
277292 ..clipBehavior = clipBehavior
278- ..delegate = delegate as TableCellDelegateMixin ;
293+ ..delegate = delegate as TableCellDelegateMixin
294+ ..alignment = alignment
295+ ..textDirection = Directionality .maybeOf (context);
279296 }
280297}
281298
@@ -299,7 +316,10 @@ class RenderTableViewport extends RenderTwoDimensionalViewport {
299316 required super .childManager,
300317 super .cacheExtent,
301318 super .clipBehavior,
302- });
319+ AlignmentGeometry alignment = Alignment .topLeft,
320+ TextDirection ? textDirection,
321+ }) : _alignment = alignment,
322+ _textDirection = textDirection;
303323
304324 @override
305325 TableCellDelegateMixin get delegate =>
@@ -309,6 +329,31 @@ class RenderTableViewport extends RenderTwoDimensionalViewport {
309329 super .delegate = value;
310330 }
311331
332+ /// The alignment of the table within the viewport when there is extra space.
333+ AlignmentGeometry get alignment => _alignment;
334+ AlignmentGeometry _alignment;
335+ set alignment (AlignmentGeometry value) {
336+ if (_alignment == value) {
337+ return ;
338+ }
339+ _alignment = value;
340+ markNeedsLayout ();
341+ }
342+
343+ /// The text direction with which to resolve [alignment] .
344+ TextDirection ? get textDirection => _textDirection;
345+ TextDirection ? _textDirection;
346+ set textDirection (TextDirection ? value) {
347+ if (_textDirection == value) {
348+ return ;
349+ }
350+ _textDirection = value;
351+ markNeedsLayout ();
352+ }
353+
354+ double _hAlignmentOffset = 0.0 ;
355+ double _vAlignmentOffset = 0.0 ;
356+
312357 // Skipped vicinities for the current frame based on merged cells.
313358 // This prevents multiple build calls for the same cell that spans multiple
314359 // vicinities.
@@ -852,6 +897,33 @@ class RenderTableViewport extends RenderTwoDimensionalViewport {
852897 _updateFirstAndLastVisibleCell ();
853898 }
854899
900+ final Alignment resolvedAlignment = alignment.resolve (textDirection);
901+ _hAlignmentOffset = 0.0 ;
902+ if (! _columnsAreInfinite && _columnMetrics.isNotEmpty) {
903+ final double totalWidth =
904+ _pinnedColumnsExtent +
905+ _columnMetrics[delegate.columnCount! - 1 ]! .trailingOffset;
906+ if (totalWidth < viewportDimension.width) {
907+ _hAlignmentOffset =
908+ (viewportDimension.width - totalWidth) *
909+ (resolvedAlignment.x + 1.0 ) /
910+ 2.0 ;
911+ }
912+ }
913+
914+ _vAlignmentOffset = 0.0 ;
915+ if (! _rowsAreInfinite && _rowMetrics.isNotEmpty) {
916+ final double totalHeight =
917+ _pinnedRowsExtent +
918+ _rowMetrics[delegate.rowCount! - 1 ]! .trailingOffset;
919+ if (totalHeight < viewportDimension.height) {
920+ _vAlignmentOffset =
921+ (viewportDimension.height - totalHeight) *
922+ (resolvedAlignment.y + 1.0 ) /
923+ 2.0 ;
924+ }
925+ }
926+
855927 if (_firstNonPinnedCell == null &&
856928 _lastPinnedRow == null &&
857929 _lastPinnedColumn == null ) {
@@ -862,19 +934,21 @@ class RenderTableViewport extends RenderTwoDimensionalViewport {
862934 final double ? offsetIntoColumn = _firstNonPinnedColumn != null
863935 ? horizontalOffset.pixels -
864936 _columnMetrics[_firstNonPinnedColumn]! .leadingOffset -
865- _pinnedColumnsExtent
937+ _pinnedColumnsExtent -
938+ _hAlignmentOffset
866939 : null ;
867940 final double ? offsetIntoRow = _firstNonPinnedRow != null
868941 ? verticalOffset.pixels -
869942 _rowMetrics[_firstNonPinnedRow]! .leadingOffset -
870- _pinnedRowsExtent
943+ _pinnedRowsExtent -
944+ _vAlignmentOffset
871945 : null ;
872946 if (_lastPinnedRow != null && _lastPinnedColumn != null ) {
873947 // Layout cells that are contained in both pinned rows and columns
874948 _layoutCells (
875949 start: TableVicinity .zero,
876950 end: TableVicinity (column: _lastPinnedColumn! , row: _lastPinnedRow! ),
877- offset: Offset .zero ,
951+ offset: Offset ( - _hAlignmentOffset, - _vAlignmentOffset) ,
878952 );
879953 }
880954
@@ -886,7 +960,7 @@ class RenderTableViewport extends RenderTwoDimensionalViewport {
886960 _layoutCells (
887961 start: TableVicinity (column: _firstNonPinnedColumn! , row: 0 ),
888962 end: TableVicinity (column: _lastNonPinnedColumn! , row: _lastPinnedRow! ),
889- offset: Offset (offsetIntoColumn! , 0 ),
963+ offset: Offset (offsetIntoColumn! , - _vAlignmentOffset ),
890964 );
891965 }
892966 if (_lastPinnedColumn != null && _firstNonPinnedRow != null ) {
@@ -897,7 +971,7 @@ class RenderTableViewport extends RenderTwoDimensionalViewport {
897971 _layoutCells (
898972 start: TableVicinity (column: 0 , row: _firstNonPinnedRow! ),
899973 end: TableVicinity (column: _lastPinnedColumn! , row: _lastNonPinnedRow! ),
900- offset: Offset (0 , offsetIntoRow! ),
974+ offset: Offset (- _hAlignmentOffset , offsetIntoRow! ),
901975 );
902976 }
903977 if (_firstNonPinnedCell != null ) {
@@ -1176,19 +1250,20 @@ class RenderTableViewport extends RenderTwoDimensionalViewport {
11761250 // follows row or column major ordering. Here is slightly different
11771251 // as we break the cells up into 4 main paint passes to clip for overlap.
11781252
1253+ final bool reversedH = axisDirectionIsReversed (horizontalAxisDirection);
1254+ final bool reversedV = axisDirectionIsReversed (verticalAxisDirection);
1255+
11791256 if (_firstNonPinnedCell != null ) {
11801257 // Paint all visible un-pinned cells
11811258 assert (_lastNonPinnedCell != null );
11821259 _clipCellsHandle.layer = context.pushClipRect (
11831260 needsCompositing,
11841261 offset,
11851262 Rect .fromLTWH (
1186- axisDirectionIsReversed (horizontalAxisDirection)
1187- ? 0.0
1188- : _pinnedColumnsExtent,
1189- axisDirectionIsReversed (verticalAxisDirection)
1190- ? 0.0
1191- : _pinnedRowsExtent,
1263+ (reversedH ? 0.0 : _pinnedColumnsExtent) +
1264+ (reversedH ? - _hAlignmentOffset : _hAlignmentOffset),
1265+ (reversedV ? 0.0 : _pinnedRowsExtent) +
1266+ (reversedV ? - _vAlignmentOffset : _vAlignmentOffset),
11921267 viewportDimension.width - _pinnedColumnsExtent,
11931268 viewportDimension.height - _pinnedRowsExtent,
11941269 ),
@@ -1214,12 +1289,13 @@ class RenderTableViewport extends RenderTwoDimensionalViewport {
12141289 needsCompositing,
12151290 offset,
12161291 Rect .fromLTWH (
1217- axisDirectionIsReversed (horizontalAxisDirection)
1218- ? viewportDimension.width - _pinnedColumnsExtent
1219- : 0.0 ,
1220- axisDirectionIsReversed (verticalAxisDirection)
1221- ? 0.0
1222- : _pinnedRowsExtent,
1292+ reversedH
1293+ ? viewportDimension.width -
1294+ _pinnedColumnsExtent -
1295+ _hAlignmentOffset
1296+ : _hAlignmentOffset,
1297+ (reversedV ? 0.0 : _pinnedRowsExtent) +
1298+ (reversedV ? - _vAlignmentOffset : _vAlignmentOffset),
12231299 _pinnedColumnsExtent,
12241300 viewportDimension.height - _pinnedRowsExtent,
12251301 ),
@@ -1248,12 +1324,11 @@ class RenderTableViewport extends RenderTwoDimensionalViewport {
12481324 needsCompositing,
12491325 offset,
12501326 Rect .fromLTWH (
1251- axisDirectionIsReversed (horizontalAxisDirection)
1252- ? 0.0
1253- : _pinnedColumnsExtent,
1254- axisDirectionIsReversed (verticalAxisDirection)
1255- ? viewportDimension.height - _pinnedRowsExtent
1256- : 0.0 ,
1327+ (reversedH ? 0.0 : _pinnedColumnsExtent) +
1328+ (reversedH ? - _hAlignmentOffset : _hAlignmentOffset),
1329+ reversedV
1330+ ? viewportDimension.height - _pinnedRowsExtent - _vAlignmentOffset
1331+ : _vAlignmentOffset,
12571332 viewportDimension.width - _pinnedColumnsExtent,
12581333 _pinnedRowsExtent,
12591334 ),
0 commit comments