From ccbfa44aea1e71483251fd290237985220964488 Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Wed, 25 Mar 2026 18:52:35 -0500 Subject: [PATCH 1/5] Implement TableView pinned extent warnings --- .../lib/src/table_view/table.dart | 49 +++++- .../pinned_extent_warning_test.dart | 166 ++++++++++++++++++ 2 files changed, 208 insertions(+), 7 deletions(-) create mode 100644 packages/two_dimensional_scrollables/test/table_view/pinned_extent_warning_test.dart diff --git a/packages/two_dimensional_scrollables/lib/src/table_view/table.dart b/packages/two_dimensional_scrollables/lib/src/table_view/table.dart index 66e5cf5ca5c..cce0f0a7f98 100644 --- a/packages/two_dimensional_scrollables/lib/src/table_view/table.dart +++ b/packages/two_dimensional_scrollables/lib/src/table_view/table.dart @@ -429,13 +429,6 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { ); } - // TODO(Piinks): Pinned rows/cols do not account for what is visible on the - // screen. Ostensibly, we would not want to have pinned rows/columns that - // extend beyond the viewport, we would never see them as they would never - // scroll into view. So this currently implementation is fairly assuming - // we will never have rows/cols that are outside of the viewport. We should - // maybe add an assertion for this during layout. - // https://github.com/flutter/flutter/issues/136833 int? get _lastPinnedRow => delegate.pinnedRowCount > 0 ? delegate.pinnedRowCount - 1 : null; int? get _lastPinnedColumn => @@ -448,6 +441,47 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { ? _columnMetrics[_lastPinnedColumn]!.trailingOffset : 0.0; + void _debugCheckPinnedExtent() { + assert(() { + if (_pinnedColumnsExtent > viewportDimension.width) { + debugPrint( + 'TableView has pinned columns with a total width of ' + '$_pinnedColumnsExtent, which exceeds the viewport width of ' + '${viewportDimension.width}. This will prevent unpinned columns ' + 'from being visible.', + ); + } else if (_pinnedColumnsExtent == viewportDimension.width) { + final bool hasUnpinnedColumns = delegate.columnCount == null || + delegate.columnCount! > delegate.pinnedColumnCount; + if (hasUnpinnedColumns) { + debugPrint( + 'TableView has pinned columns that fully consume the viewport width. ' + 'Unpinned columns will not be visible.', + ); + } + } + + if (_pinnedRowsExtent > viewportDimension.height) { + debugPrint( + 'TableView has pinned rows with a total height of ' + '$_pinnedRowsExtent, which exceeds the viewport height of ' + '${viewportDimension.height}. This will prevent unpinned rows ' + 'from being visible.', + ); + } else if (_pinnedRowsExtent == viewportDimension.height) { + final bool hasUnpinnedRows = delegate.rowCount == null || + delegate.rowCount! > delegate.pinnedRowCount; + if (hasUnpinnedRows) { + debugPrint( + 'TableView has pinned rows that fully consume the viewport height. ' + 'Unpinned rows will not be visible.', + ); + } + } + return true; + }()); + } + @override TableViewParentData parentDataOf(RenderBox child) => super.parentDataOf(child) as TableViewParentData; @@ -892,6 +926,7 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { _updateColumnMetrics(); _updateRowMetrics(); _updateScrollBounds(); + _debugCheckPinnedExtent(); } else { // Updates the visible cells based on cached table metrics. _updateFirstAndLastVisibleCell(); diff --git a/packages/two_dimensional_scrollables/test/table_view/pinned_extent_warning_test.dart b/packages/two_dimensional_scrollables/test/table_view/pinned_extent_warning_test.dart new file mode 100644 index 00000000000..cc34a4af623 --- /dev/null +++ b/packages/two_dimensional_scrollables/test/table_view/pinned_extent_warning_test.dart @@ -0,0 +1,166 @@ +// Copyright 2013 The Flutter Authors +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:two_dimensional_scrollables/two_dimensional_scrollables.dart'; + +void main() { + group('TableView pinned extent warnings', () { + testWidgets('Warns when pinned columns exceed viewport width', (WidgetTester tester) async { + final List log = []; + final DebugPrintCallback oldDebugPrint = debugPrint; + debugPrint = (String? message, {int? wrapWidth}) { + log.add(message!); + }; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: SizedBox( + width: 200, + height: 400, + child: TableView.builder( + columnCount: 5, + rowCount: 5, + pinnedColumnCount: 3, + columnBuilder: (int index) => const TableSpan(extent: FixedTableSpanExtent(100)), + rowBuilder: (int index) => const TableSpan(extent: FixedTableSpanExtent(100)), + cellBuilder: (BuildContext context, TableVicinity vicinity) => const TableViewCell(child: SizedBox.shrink()), + ), + ), + ), + ), + ); + + // Pinned columns extent = 300, viewport width = 200. + expect(log, contains(contains('TableView has pinned columns with a total width of 300.0, which exceeds the viewport width of 200.0'))); + debugPrint = oldDebugPrint; + }); + + testWidgets('Warns when pinned rows exceed viewport height', (WidgetTester tester) async { + final List log = []; + final DebugPrintCallback oldDebugPrint = debugPrint; + debugPrint = (String? message, {int? wrapWidth}) { + log.add(message!); + }; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: SizedBox( + width: 400, + height: 200, + child: TableView.builder( + columnCount: 5, + rowCount: 5, + pinnedRowCount: 3, + columnBuilder: (int index) => const TableSpan(extent: FixedTableSpanExtent(100)), + rowBuilder: (int index) => const TableSpan(extent: FixedTableSpanExtent(100)), + cellBuilder: (BuildContext context, TableVicinity vicinity) => const TableViewCell(child: SizedBox.shrink()), + ), + ), + ), + ), + ); + + // Pinned rows extent = 300, viewport height = 200. + expect(log, contains(contains('TableView has pinned rows with a total height of 300.0, which exceeds the viewport height of 200.0'))); + debugPrint = oldDebugPrint; + }); + + testWidgets('Warns when pinned columns fully consume viewport width and there are unpinned columns', (WidgetTester tester) async { + final List log = []; + final DebugPrintCallback oldDebugPrint = debugPrint; + debugPrint = (String? message, {int? wrapWidth}) { + log.add(message!); + }; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: SizedBox( + width: 200, + height: 400, + child: TableView.builder( + columnCount: 3, + rowCount: 5, + pinnedColumnCount: 2, + columnBuilder: (int index) => const TableSpan(extent: FixedTableSpanExtent(100)), + rowBuilder: (int index) => const TableSpan(extent: FixedTableSpanExtent(100)), + cellBuilder: (BuildContext context, TableVicinity vicinity) => const TableViewCell(child: SizedBox.shrink()), + ), + ), + ), + ), + ); + + // Pinned columns extent = 200, viewport width = 200. Unpinned columns = 1. + expect(log, contains('TableView has pinned columns that fully consume the viewport width. Unpinned columns will not be visible.')); + debugPrint = oldDebugPrint; + }); + + testWidgets('Warns when pinned rows fully consume viewport height and there are unpinned rows', (WidgetTester tester) async { + final List log = []; + final DebugPrintCallback oldDebugPrint = debugPrint; + debugPrint = (String? message, {int? wrapWidth}) { + log.add(message!); + }; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: SizedBox( + width: 400, + height: 200, + child: TableView.builder( + columnCount: 5, + rowCount: 3, + pinnedRowCount: 2, + columnBuilder: (int index) => const TableSpan(extent: FixedTableSpanExtent(100)), + rowBuilder: (int index) => const TableSpan(extent: FixedTableSpanExtent(100)), + cellBuilder: (BuildContext context, TableVicinity vicinity) => const TableViewCell(child: SizedBox.shrink()), + ), + ), + ), + ), + ); + + // Pinned rows extent = 200, viewport height = 200. Unpinned rows = 1. + expect(log, contains('TableView has pinned rows that fully consume the viewport height. Unpinned rows will not be visible.')); + debugPrint = oldDebugPrint; + }); + + testWidgets('Does not warn when all columns are pinned even if they consume viewport', (WidgetTester tester) async { + final List log = []; + final DebugPrintCallback oldDebugPrint = debugPrint; + debugPrint = (String? message, {int? wrapWidth}) { + log.add(message!); + }; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: SizedBox( + width: 200, + height: 400, + child: TableView.builder( + columnCount: 2, + rowCount: 5, + pinnedColumnCount: 2, + columnBuilder: (int index) => const TableSpan(extent: FixedTableSpanExtent(100)), + rowBuilder: (int index) => const TableSpan(extent: FixedTableSpanExtent(100)), + cellBuilder: (BuildContext context, TableVicinity vicinity) => const TableViewCell(child: SizedBox.shrink()), + ), + ), + ), + ), + ); + + expect(log, isNot(contains(contains('Unpinned columns will not be visible')))); + debugPrint = oldDebugPrint; + }); + }); +} From b1b2a41bda8616b2c71b8d984040ea8acd0bff09 Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Wed, 25 Mar 2026 18:54:37 -0500 Subject: [PATCH 2/5] Bump version to 0.4.1 and update CHANGELOG --- packages/two_dimensional_scrollables/CHANGELOG.md | 4 ++++ packages/two_dimensional_scrollables/pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/two_dimensional_scrollables/CHANGELOG.md b/packages/two_dimensional_scrollables/CHANGELOG.md index 6d84270e8b6..2f031898ab4 100644 --- a/packages/two_dimensional_scrollables/CHANGELOG.md +++ b/packages/two_dimensional_scrollables/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.4.1 + +* Adds warnings for TableView pinned rows and columns that exceed the viewport dimensions. + ## 0.4.0 * Added `alignment` property to `TableView` and `TreeView` to align content within the viewport when it is smaller than the viewport extent. diff --git a/packages/two_dimensional_scrollables/pubspec.yaml b/packages/two_dimensional_scrollables/pubspec.yaml index 8525e06bff9..8e6d131bc8e 100644 --- a/packages/two_dimensional_scrollables/pubspec.yaml +++ b/packages/two_dimensional_scrollables/pubspec.yaml @@ -1,6 +1,6 @@ name: two_dimensional_scrollables description: Widgets that scroll using the two dimensional scrolling foundation. -version: 0.4.0 +version: 0.4.1 repository: https://github.com/flutter/packages/tree/main/packages/two_dimensional_scrollables issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+two_dimensional_scrollables%22+ From 31f716e39ef2e8c60d0e7ffa09f209e0ca619c5a Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Thu, 26 Mar 2026 10:16:51 -0500 Subject: [PATCH 3/5] Format --- .../lib/src/table_view/table.dart | 6 +- .../pinned_extent_warning_test.dart | 239 +++++++++++------- 2 files changed, 151 insertions(+), 94 deletions(-) diff --git a/packages/two_dimensional_scrollables/lib/src/table_view/table.dart b/packages/two_dimensional_scrollables/lib/src/table_view/table.dart index cce0f0a7f98..b09a7898e85 100644 --- a/packages/two_dimensional_scrollables/lib/src/table_view/table.dart +++ b/packages/two_dimensional_scrollables/lib/src/table_view/table.dart @@ -451,7 +451,8 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { 'from being visible.', ); } else if (_pinnedColumnsExtent == viewportDimension.width) { - final bool hasUnpinnedColumns = delegate.columnCount == null || + final bool hasUnpinnedColumns = + delegate.columnCount == null || delegate.columnCount! > delegate.pinnedColumnCount; if (hasUnpinnedColumns) { debugPrint( @@ -469,7 +470,8 @@ class RenderTableViewport extends RenderTwoDimensionalViewport { 'from being visible.', ); } else if (_pinnedRowsExtent == viewportDimension.height) { - final bool hasUnpinnedRows = delegate.rowCount == null || + final bool hasUnpinnedRows = + delegate.rowCount == null || delegate.rowCount! > delegate.pinnedRowCount; if (hasUnpinnedRows) { debugPrint( diff --git a/packages/two_dimensional_scrollables/test/table_view/pinned_extent_warning_test.dart b/packages/two_dimensional_scrollables/test/table_view/pinned_extent_warning_test.dart index cc34a4af623..2bd6d8517e5 100644 --- a/packages/two_dimensional_scrollables/test/table_view/pinned_extent_warning_test.dart +++ b/packages/two_dimensional_scrollables/test/table_view/pinned_extent_warning_test.dart @@ -9,8 +9,10 @@ import 'package:two_dimensional_scrollables/two_dimensional_scrollables.dart'; void main() { group('TableView pinned extent warnings', () { - testWidgets('Warns when pinned columns exceed viewport width', (WidgetTester tester) async { - final List log = []; + testWidgets('Warns when pinned columns exceed viewport width', ( + WidgetTester tester, + ) async { + final log = []; final DebugPrintCallback oldDebugPrint = debugPrint; debugPrint = (String? message, {int? wrapWidth}) { log.add(message!); @@ -26,9 +28,12 @@ void main() { columnCount: 5, rowCount: 5, pinnedColumnCount: 3, - columnBuilder: (int index) => const TableSpan(extent: FixedTableSpanExtent(100)), - rowBuilder: (int index) => const TableSpan(extent: FixedTableSpanExtent(100)), - cellBuilder: (BuildContext context, TableVicinity vicinity) => const TableViewCell(child: SizedBox.shrink()), + columnBuilder: (int index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + rowBuilder: (int index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + cellBuilder: (BuildContext context, TableVicinity vicinity) => + const TableViewCell(child: SizedBox.shrink()), ), ), ), @@ -36,12 +41,21 @@ void main() { ); // Pinned columns extent = 300, viewport width = 200. - expect(log, contains(contains('TableView has pinned columns with a total width of 300.0, which exceeds the viewport width of 200.0'))); + expect( + log, + contains( + contains( + 'TableView has pinned columns with a total width of 300.0, which exceeds the viewport width of 200.0', + ), + ), + ); debugPrint = oldDebugPrint; }); - testWidgets('Warns when pinned rows exceed viewport height', (WidgetTester tester) async { - final List log = []; + testWidgets('Warns when pinned rows exceed viewport height', ( + WidgetTester tester, + ) async { + final log = []; final DebugPrintCallback oldDebugPrint = debugPrint; debugPrint = (String? message, {int? wrapWidth}) { log.add(message!); @@ -57,9 +71,12 @@ void main() { columnCount: 5, rowCount: 5, pinnedRowCount: 3, - columnBuilder: (int index) => const TableSpan(extent: FixedTableSpanExtent(100)), - rowBuilder: (int index) => const TableSpan(extent: FixedTableSpanExtent(100)), - cellBuilder: (BuildContext context, TableVicinity vicinity) => const TableViewCell(child: SizedBox.shrink()), + columnBuilder: (int index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + rowBuilder: (int index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + cellBuilder: (BuildContext context, TableVicinity vicinity) => + const TableViewCell(child: SizedBox.shrink()), ), ), ), @@ -67,100 +84,138 @@ void main() { ); // Pinned rows extent = 300, viewport height = 200. - expect(log, contains(contains('TableView has pinned rows with a total height of 300.0, which exceeds the viewport height of 200.0'))); - debugPrint = oldDebugPrint; - }); - - testWidgets('Warns when pinned columns fully consume viewport width and there are unpinned columns', (WidgetTester tester) async { - final List log = []; - final DebugPrintCallback oldDebugPrint = debugPrint; - debugPrint = (String? message, {int? wrapWidth}) { - log.add(message!); - }; - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: SizedBox( - width: 200, - height: 400, - child: TableView.builder( - columnCount: 3, - rowCount: 5, - pinnedColumnCount: 2, - columnBuilder: (int index) => const TableSpan(extent: FixedTableSpanExtent(100)), - rowBuilder: (int index) => const TableSpan(extent: FixedTableSpanExtent(100)), - cellBuilder: (BuildContext context, TableVicinity vicinity) => const TableViewCell(child: SizedBox.shrink()), - ), - ), + expect( + log, + contains( + contains( + 'TableView has pinned rows with a total height of 300.0, which exceeds the viewport height of 200.0', ), ), ); - - // Pinned columns extent = 200, viewport width = 200. Unpinned columns = 1. - expect(log, contains('TableView has pinned columns that fully consume the viewport width. Unpinned columns will not be visible.')); debugPrint = oldDebugPrint; }); - testWidgets('Warns when pinned rows fully consume viewport height and there are unpinned rows', (WidgetTester tester) async { - final List log = []; - final DebugPrintCallback oldDebugPrint = debugPrint; - debugPrint = (String? message, {int? wrapWidth}) { - log.add(message!); - }; - - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: SizedBox( - width: 400, - height: 200, - child: TableView.builder( - columnCount: 5, - rowCount: 3, - pinnedRowCount: 2, - columnBuilder: (int index) => const TableSpan(extent: FixedTableSpanExtent(100)), - rowBuilder: (int index) => const TableSpan(extent: FixedTableSpanExtent(100)), - cellBuilder: (BuildContext context, TableVicinity vicinity) => const TableViewCell(child: SizedBox.shrink()), + testWidgets( + 'Warns when pinned columns fully consume viewport width and there are unpinned columns', + (WidgetTester tester) async { + final log = []; + final DebugPrintCallback oldDebugPrint = debugPrint; + debugPrint = (String? message, {int? wrapWidth}) { + log.add(message!); + }; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: SizedBox( + width: 200, + height: 400, + child: TableView.builder( + columnCount: 3, + rowCount: 5, + pinnedColumnCount: 2, + columnBuilder: (int index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + rowBuilder: (int index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + cellBuilder: (BuildContext context, TableVicinity vicinity) => + const TableViewCell(child: SizedBox.shrink()), + ), ), ), ), - ), - ); - - // Pinned rows extent = 200, viewport height = 200. Unpinned rows = 1. - expect(log, contains('TableView has pinned rows that fully consume the viewport height. Unpinned rows will not be visible.')); - debugPrint = oldDebugPrint; - }); - - testWidgets('Does not warn when all columns are pinned even if they consume viewport', (WidgetTester tester) async { - final List log = []; - final DebugPrintCallback oldDebugPrint = debugPrint; - debugPrint = (String? message, {int? wrapWidth}) { - log.add(message!); - }; + ); - await tester.pumpWidget( - MaterialApp( - home: Scaffold( - body: SizedBox( - width: 200, - height: 400, - child: TableView.builder( - columnCount: 2, - rowCount: 5, - pinnedColumnCount: 2, - columnBuilder: (int index) => const TableSpan(extent: FixedTableSpanExtent(100)), - rowBuilder: (int index) => const TableSpan(extent: FixedTableSpanExtent(100)), - cellBuilder: (BuildContext context, TableVicinity vicinity) => const TableViewCell(child: SizedBox.shrink()), + // Pinned columns extent = 200, viewport width = 200. Unpinned columns = 1. + expect( + log, + contains( + 'TableView has pinned columns that fully consume the viewport width. Unpinned columns will not be visible.', + ), + ); + debugPrint = oldDebugPrint; + }, + ); + + testWidgets( + 'Warns when pinned rows fully consume viewport height and there are unpinned rows', + (WidgetTester tester) async { + final log = []; + final DebugPrintCallback oldDebugPrint = debugPrint; + debugPrint = (String? message, {int? wrapWidth}) { + log.add(message!); + }; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: SizedBox( + width: 400, + height: 200, + child: TableView.builder( + columnCount: 5, + rowCount: 3, + pinnedRowCount: 2, + columnBuilder: (int index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + rowBuilder: (int index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + cellBuilder: (BuildContext context, TableVicinity vicinity) => + const TableViewCell(child: SizedBox.shrink()), + ), ), ), ), - ), - ); + ); - expect(log, isNot(contains(contains('Unpinned columns will not be visible')))); - debugPrint = oldDebugPrint; - }); + // Pinned rows extent = 200, viewport height = 200. Unpinned rows = 1. + expect( + log, + contains( + 'TableView has pinned rows that fully consume the viewport height. Unpinned rows will not be visible.', + ), + ); + debugPrint = oldDebugPrint; + }, + ); + + testWidgets( + 'Does not warn when all columns are pinned even if they consume viewport', + (WidgetTester tester) async { + final log = []; + final DebugPrintCallback oldDebugPrint = debugPrint; + debugPrint = (String? message, {int? wrapWidth}) { + log.add(message!); + }; + + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: SizedBox( + width: 200, + height: 400, + child: TableView.builder( + columnCount: 2, + rowCount: 5, + pinnedColumnCount: 2, + columnBuilder: (int index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + rowBuilder: (int index) => + const TableSpan(extent: FixedTableSpanExtent(100)), + cellBuilder: (BuildContext context, TableVicinity vicinity) => + const TableViewCell(child: SizedBox.shrink()), + ), + ), + ), + ), + ); + + expect( + log, + isNot(contains(contains('Unpinned columns will not be visible'))), + ); + debugPrint = oldDebugPrint; + }, + ); }); } From 8df6bb8f393858b28fc8db9ff2a8bb3b5e05253a Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Thu, 26 Mar 2026 10:29:36 -0500 Subject: [PATCH 4/5] Test clean up --- .../pinned_extent_warning_test.dart | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/packages/two_dimensional_scrollables/test/table_view/pinned_extent_warning_test.dart b/packages/two_dimensional_scrollables/test/table_view/pinned_extent_warning_test.dart index 2bd6d8517e5..5d141f20a25 100644 --- a/packages/two_dimensional_scrollables/test/table_view/pinned_extent_warning_test.dart +++ b/packages/two_dimensional_scrollables/test/table_view/pinned_extent_warning_test.dart @@ -12,6 +12,7 @@ void main() { testWidgets('Warns when pinned columns exceed viewport width', ( WidgetTester tester, ) async { + // Regression test for https://github.com/flutter/flutter/issues/136833 final log = []; final DebugPrintCallback oldDebugPrint = debugPrint; debugPrint = (String? message, {int? wrapWidth}) { @@ -40,7 +41,9 @@ void main() { ), ); - // Pinned columns extent = 300, viewport width = 200. + // Pinned columns extent = 300 (3 * 100), viewport width = 200. + // A warning is expected because the pinned columns are wider than the + // viewport, meaning even the pinned content cannot be fully displayed. expect( log, contains( @@ -55,6 +58,7 @@ void main() { testWidgets('Warns when pinned rows exceed viewport height', ( WidgetTester tester, ) async { + // Regression test for https://github.com/flutter/flutter/issues/136833 final log = []; final DebugPrintCallback oldDebugPrint = debugPrint; debugPrint = (String? message, {int? wrapWidth}) { @@ -83,7 +87,9 @@ void main() { ), ); - // Pinned rows extent = 300, viewport height = 200. + // Pinned rows extent = 300 (3 * 100), viewport height = 200. + // A warning is expected because the pinned rows are taller than the + // viewport, meaning even the pinned content cannot be fully displayed. expect( log, contains( @@ -98,6 +104,7 @@ void main() { testWidgets( 'Warns when pinned columns fully consume viewport width and there are unpinned columns', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/136833 final log = []; final DebugPrintCallback oldDebugPrint = debugPrint; debugPrint = (String? message, {int? wrapWidth}) { @@ -126,7 +133,10 @@ void main() { ), ); - // Pinned columns extent = 200, viewport width = 200. Unpinned columns = 1. + // Pinned columns extent = 200 (2 * 100), viewport width = 200. + // There is 1 unpinned column (columnCount: 3, pinnedColumnCount: 2). + // Since the pinned columns take up the entire viewport width, the + // unpinned column will never be visible during scrolling. expect( log, contains( @@ -140,6 +150,7 @@ void main() { testWidgets( 'Warns when pinned rows fully consume viewport height and there are unpinned rows', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/136833 final log = []; final DebugPrintCallback oldDebugPrint = debugPrint; debugPrint = (String? message, {int? wrapWidth}) { @@ -168,7 +179,10 @@ void main() { ), ); - // Pinned rows extent = 200, viewport height = 200. Unpinned rows = 1. + // Pinned rows extent = 200 (2 * 100), viewport height = 200. + // There is 1 unpinned row (rowCount: 3, pinnedRowCount: 2). + // Since the pinned rows take up the entire viewport height, the + // unpinned row will never be visible during scrolling. expect( log, contains( @@ -182,6 +196,7 @@ void main() { testWidgets( 'Does not warn when all columns are pinned even if they consume viewport', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/136833 final log = []; final DebugPrintCallback oldDebugPrint = debugPrint; debugPrint = (String? message, {int? wrapWidth}) { @@ -210,6 +225,11 @@ void main() { ), ); + // Pinned columns extent = 200 (2 * 100), viewport width = 200. + // Although the pinned columns fully consume the viewport width, + // ALL columns are pinned (columnCount: 2, pinnedColumnCount: 2). + // Since there are no unpinned columns, no warning is issued about + // unpinned columns being hidden. expect( log, isNot(contains(contains('Unpinned columns will not be visible'))), From ff29b7b765a001dcd26b9bab369cf8add821e06d Mon Sep 17 00:00:00 2001 From: Kate Lovett Date: Thu, 26 Mar 2026 15:38:37 -0500 Subject: [PATCH 5/5] Fix test strings --- .../test/table_view/pinned_extent_warning_test.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/two_dimensional_scrollables/test/table_view/pinned_extent_warning_test.dart b/packages/two_dimensional_scrollables/test/table_view/pinned_extent_warning_test.dart index 5d141f20a25..af0d6625b6e 100644 --- a/packages/two_dimensional_scrollables/test/table_view/pinned_extent_warning_test.dart +++ b/packages/two_dimensional_scrollables/test/table_view/pinned_extent_warning_test.dart @@ -47,8 +47,8 @@ void main() { expect( log, contains( - contains( - 'TableView has pinned columns with a total width of 300.0, which exceeds the viewport width of 200.0', + matches( + r'TableView has pinned columns with a total width of 300(\.0)?, which exceeds the viewport width of 200(\.0)?', ), ), ); @@ -93,8 +93,8 @@ void main() { expect( log, contains( - contains( - 'TableView has pinned rows with a total height of 300.0, which exceeds the viewport height of 200.0', + matches( + r'TableView has pinned rows with a total height of 300(\.0)?, which exceeds the viewport height of 200(\.0)?', ), ), );