Repository navigation
[two_dimensional_scrollables] Exclude trailing pinned spans from the non-pinned range - #12666
Conversation
…non-pinned range RenderTableViewport lays out and paints the table as nine regions: leading pinned, regular and trailing pinned rows crossed with the same three column categories. _updateFirstAndLastVisibleCell binary searches for the last regular row and column of the visible range, and when no regular span reaches the trailing edge of the layout target it fell back to the last index in the metrics map, which is a trailing pinned span whenever trailingPinnedRowCount or trailingPinnedColumnCount is greater than zero. The regular range then overlapped the trailing pinned range, so the same vicinity was visited by two regions in a single layout and paint pass. That wastes work, and it also throws: "Expected to re-use an element at ...", "TableViewCell for ... could not be found", and a null paintOffset while computing span decoration bounds. _updateColumnMetrics and _updateRowMetrics already cap the range with the same rule that _lastRegularColumnIndex and _lastRegularRowIndex express, so this reuses those getters and keeps the old fallback for the infinite case where they are null and trailing pinned spans cannot exist. Fixes flutter/flutter#185842
|
Warning You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again! |
|
@Piinks friendly ping — this has been open since Aug 28 with green CI. It's a small fix, happy to rebase or adjust if anything is needed. |
And just assigned for review yesterday. Thanks for your patience. 🙂 |
Piinks
left a comment
There was a problem hiding this comment.
Thanks for this! Can you add test coverage for when there is both pinned trailing rows and columns?
…ogether Covers a table with both trailingPinnedRowCount and trailingPinnedColumnCount scrolled to the end on both axes, as requested in review. Without the fix this throws "Expected to re-use an element at (row: 13, column: 19)".
|
Added in aedd88c — covers both trailing pinned rows and columns scrolled to the end; it fails without the fix. |
…le range _binarySearchFirstFromMap searched the whole metrics map, but trailing pinned spans sit at its end and fail the regular-span condition, so the condition is not monotonic across the map. Whenever the search probed a trailing pinned span it discarded the regular spans before it: with columnCount: 3 and trailingPinnedColumnCount: 2, a scroll left no regular column in the visible range and its cells disappeared. Restrict the search to the indices of the regular spans, and cover more than one trailing pinned row and column.
…nned-double-layout # Conflicts: # packages/two_dimensional_scrollables/CHANGELOG.md
|
Also pushed 2826fb1: |
tarrinneal
left a comment
There was a problem hiding this comment.
I might just be dumb, but that comment was hard to read. I won't prevent this from landing over it, but it might be worth a quick rewrite.
b734779 to
835ab6f
Compare
flutter/packages@e55e7ac...ba0364a 2026-09-26 stuartmorgan@google.com [google_maps_flutter] Indicate that default iOS impl is discoraged (flutter/packages#12872) 2026-09-26 36861262+QuncCccccc@users.noreply.github.com [material_ui] Add Material 3 Expressive IconButton (flutter/packages#12832) 2026-09-25 jessiewong401@gmail.com Plugin example apps to 9.3.1 (flutter/packages#13019) 2026-09-25 36861262+QuncCccccc@users.noreply.github.com [material_ui] Don't clip MenuItemButton.leadingIcon (flutter/packages#12986) 2026-09-25 36861262+QuncCccccc@users.noreply.github.com [material_ui] Migrate M3 ExpansionTile template to use new gen_defaults (flutter/packages#12920) 2026-09-25 149176071+m1roxx@users.noreply.github.com [two_dimensional_scrollables] Exclude trailing pinned spans from the non-pinned range (flutter/packages#12666) 2026-09-25 36861262+QuncCccccc@users.noreply.github.com [material_ui] Migrate M3 Drawer template to use new gen_defaults (flutter/packages#12916) 2026-09-25 36861262+QuncCccccc@users.noreply.github.com [material_ui] Migrate M3 Divider template to use new gen_defaults (flutter/packages#12915) 2026-09-25 instantni.med@gmail.com [google_maps_flutter_web] Fix AdvancedMarker anchors on web (flutter/packages#11966) If this roll has caused a breakage, revert this CL and set the roller to dry run mode using the controls here: https://autoroll.skia.org/r/flutter-packages-flutter-autoroll Please CC flutter-ecosystem@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
RenderTableViewportlays out and paints the table as nine regions: leading pinned, regular andtrailing pinned rows, each crossed with the same three column categories.
_updateFirstAndLastVisibleCellbinary searches for the last regular row and column of the visiblerange, and when no regular span reaches the trailing edge of the layout target it fell back to the
last index in the metrics map:
Whenever
trailingPinnedRowCountortrailingPinnedColumnCountis greater than zero, that lastindex is a trailing pinned span. The regular range then overlaps the trailing pinned range, and
the same
TableVicinityis visited by two regions in a single layout and paint pass._updateColumnMetricsand_updateRowMetricsalready cap the same value correctly, with the rulethat
_lastRegularColumnIndexand_lastRegularRowIndexexpress, so the two code paths disagreed.This PR makes
_updateFirstAndLastVisibleCelluse those getters. The old fallback is kept for thecase where they are null — infinite spans with no null terminator — where trailing pinned spans
cannot exist, since
_firstTrailingPinnedColumnand_firstTrailingPinnedRowboth require anon-null span count.
Fixes flutter/flutter#185842
Fixes flutter/flutter#190800
Beyond the duplicated work
The overlap is not only wasted layout. Scrolling a table to the end with a trailing pinned span
throws, because two regions claim the same cell:
and, once the spans carry a decoration, the non-pinned region reaches a cell whose
paintOffsetwasnever set for it:
Dragging through a 60x60 table with pinned and trailing pinned rows and columns throws
Expected to re-use an element at ...andTableViewCell for (row: 1, column: 58) could not be foundbefore this change, and nothing after it. That is the same subsystem and trigger asflutter/flutter#190800, but the specific assertion reported there did not
reproduce in my runs, so I am not claiming this fixes it.
Tests
Two regression tests are added to
table_test.dart, one per axis. Each scrolls a table with atrailing pinned span to the end, asserts that no exception is thrown, and asserts that the trailing
pinned span's decoration is painted exactly once — by the trailing pinned region only. Both fail
before this change.
Counting
cellBuildercalls does not work as a test here:buildOrObtainChildForcaches childrenfor the frame and
RenderObject.layoutearly-returns on unchanged constraints, so the duplicatedvisit is invisible from the delegate. The new
CountingSpanDecorationhelper observes it throughthe public
TableSpanDecoration.paintAPI instead.Pre-Review Checklist
[shared_preferences]///).Footnotes
Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling. ↩ ↩2