[two_dimensional_scrollables] Fix pinned cells hit test#11777
Conversation
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
There was a problem hiding this comment.
Code Review
This pull request modifies RenderTableViewport to ensure hit testing correctly accounts for pinned areas by intersecting cell rectangles with section-specific clip rectangles. It introduces a _sectionClipRectFor method to calculate these bounds and adds regression tests to verify hit-test precedence for pinned cells. Review feedback suggests optimizing hit testing by using dual contains checks to avoid unnecessary object allocations and caching viewportDimension in _sectionClipRectFor to improve readability and performance.
| final Rect clippedCellRect = cellRect.intersect( | ||
| _sectionClipRectFor(cellParentData.tableVicinity), | ||
| ); | ||
| if (clippedCellRect.contains(position)) { |
There was a problem hiding this comment.
To avoid unnecessary object allocation during hit testing, you can replace the intersect call with a combined contains check. Rect.intersect creates a new Rect object, which is not needed here since you only need to verify if the position is within both rectangles. This is a common optimization in hit testing paths to reduce pressure on the garbage collector.
if (cellRect.contains(position) &&
_sectionClipRectFor(cellParentData.tableVicinity).contains(position)) {| // a cell belongs to (leading-pinned, non-pinned, or trailing-pinned for each | ||
| // axis). Intersecting the raw cell rect with this rect in hitTestChildren | ||
| // prevents scrollable cells from capturing taps inside pinned areas. | ||
| Rect _sectionClipRectFor(TableVicinity vicinity) { |
There was a problem hiding this comment.
f3a106c to
782e898
Compare
b77e6e5 to
ee38453
Compare
Piinks
left a comment
There was a problem hiding this comment.
Hey @beroso thanks so much for the fix!
It looks like there may be an edge case this does not account for. The implementation of _sectionClipRectFor calculates clip boundaries without factoring in the viewport alignment offsets (_hAlignmentOffset and _vAlignmentOffset).
When the table is smaller than the viewport and configured with a custom alignment (e.g., alignment: Alignment.center), cells and clip rects are shifted by the alignment offsets. For hit testing, cells are shifted (via their paintOffset), but _sectionClipRectFor returns an un-shifted clip rect. This means hit testing on pinned cells in aligned tables fails, as the tap position falls outside of the un-shifted clip rect.
I wrote a regression test to include and verify:
Details
Add the new regression test verifying hit-testing on aligned pinned columns:
testWidgets('Tapping on a pinned column in an aligned table (with _hAlignmentOffset) registers correctly', (
WidgetTester tester,
) async {
TableVicinity? lastTapped;
await tester.pumpWidget(
MaterialApp(
home: Scaffold(
body: SizedBox(
height: 400,
width: 400,
child: TableView.builder(
cacheExtent: 0.0,
columnCount: 3,
rowCount: 1,
pinnedColumnCount: 1,
alignment: Alignment.center,
columnBuilder: (_) => const TableSpan(extent: FixedTableSpanExtent(100)),
rowBuilder: (_) => const TableSpan(extent: FixedTableSpanExtent(100)),
cellBuilder: (_, TableVicinity vicinity) {
return TableViewCell(
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => lastTapped = vicinity,
child: const SizedBox.expand(),
),
);
},
),
),
),
),
);
// Pinned column 0 is at x = 50..150 due to Alignment.center. Tap at (100, 200).
await tester.tapAt(const Offset(100, 200));
await tester.pumpAndSettle();
expect(
lastTapped,
TableVicinity.zero,
reason: 'Tapping at x=100 (inside aligned pinned column 0) should register a tap on column 0.',
);
});|
Hi @Piinks thanks for the feedback! |
This fixes a bug where TableView trailing pinned cells lose hit tests to underlying cells.
That glitch makes one of the main use cases unworkable (action columns at the right edge of the data grid).
Fix flutter/flutter#186876
Pre-Review Checklist
[shared_preferences]///).If you need help, consider asking for advice on the #hackers-new channel on Discord.
Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the
gemini-code-assistbot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.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