@@ -581,7 +581,13 @@ class RenderTableViewport extends RenderTwoDimensionalViewport {
581581 continue ;
582582 }
583583 final Rect cellRect = cellParentData.paintOffset! & cell.size;
584- if (cellRect.contains (position)) {
584+ // Intersect with the section clip rect for this cell to prevent
585+ // scrollable cells from stealing hits inside the trailing pinned area.
586+ // This mirrors the pushClipRect applied to each section during painting.
587+ final Rect clippedCellRect = cellRect.intersect (
588+ _sectionClipRectFor (cellParentData.tableVicinity),
589+ );
590+ if (clippedCellRect.contains (position)) {
585591 result.addWithPaintOffset (
586592 offset: cellParentData.paintOffset,
587593 position: position,
@@ -619,6 +625,79 @@ class RenderTableViewport extends RenderTwoDimensionalViewport {
619625 return false ;
620626 }
621627
628+ // Returns the viewport-space clip rect that painting applies to the section
629+ // a cell belongs to (leading-pinned, non-pinned, or trailing-pinned for each
630+ // axis). Intersecting the raw cell rect with this rect in hitTestChildren
631+ // prevents scrollable cells from capturing taps inside pinned areas.
632+ Rect _sectionClipRectFor (TableVicinity vicinity) {
633+ final bool reversedH = axisDirectionIsReversed (horizontalAxisDirection);
634+ final bool reversedV = axisDirectionIsReversed (verticalAxisDirection);
635+
636+ final double colLeft, colRight;
637+ if (vicinity.column < delegate.pinnedColumnCount) {
638+ // Leading pinned column — visually on the right when axis is reversed.
639+ if (reversedH) {
640+ colLeft = viewportDimension.width - _leadingPinnedColumnsExtent;
641+ colRight = viewportDimension.width;
642+ } else {
643+ colLeft = 0.0 ;
644+ colRight = _leadingPinnedColumnsExtent;
645+ }
646+ } else if (_firstTrailingPinnedColumn != null &&
647+ vicinity.column >= _firstTrailingPinnedColumn! ) {
648+ // Trailing pinned column — visually on the left when axis is reversed.
649+ if (reversedH) {
650+ colLeft = 0.0 ;
651+ colRight = _trailingPinnedColumnsExtent;
652+ } else {
653+ colLeft = viewportDimension.width - _trailingPinnedColumnsExtent;
654+ colRight = viewportDimension.width;
655+ }
656+ } else {
657+ // Non-pinned column.
658+ if (reversedH) {
659+ colLeft = _trailingPinnedColumnsExtent;
660+ colRight = viewportDimension.width - _leadingPinnedColumnsExtent;
661+ } else {
662+ colLeft = _leadingPinnedColumnsExtent;
663+ colRight = viewportDimension.width - _trailingPinnedColumnsExtent;
664+ }
665+ }
666+
667+ final double rowTop, rowBottom;
668+ if (vicinity.row < delegate.pinnedRowCount) {
669+ // Leading pinned row — visually on the bottom when axis is reversed.
670+ if (reversedV) {
671+ rowTop = viewportDimension.height - _leadingPinnedRowsExtent;
672+ rowBottom = viewportDimension.height;
673+ } else {
674+ rowTop = 0.0 ;
675+ rowBottom = _leadingPinnedRowsExtent;
676+ }
677+ } else if (_firstTrailingPinnedRow != null &&
678+ vicinity.row >= _firstTrailingPinnedRow! ) {
679+ // Trailing pinned row — visually on the top when axis is reversed.
680+ if (reversedV) {
681+ rowTop = 0.0 ;
682+ rowBottom = _trailingPinnedRowsExtent;
683+ } else {
684+ rowTop = viewportDimension.height - _trailingPinnedRowsExtent;
685+ rowBottom = viewportDimension.height;
686+ }
687+ } else {
688+ // Non-pinned row.
689+ if (reversedV) {
690+ rowTop = _trailingPinnedRowsExtent;
691+ rowBottom = viewportDimension.height - _leadingPinnedRowsExtent;
692+ } else {
693+ rowTop = _leadingPinnedRowsExtent;
694+ rowBottom = viewportDimension.height - _trailingPinnedRowsExtent;
695+ }
696+ }
697+
698+ return Rect .fromLTRB (colLeft, rowTop, colRight, rowBottom);
699+ }
700+
622701 // Updates the cached column metrics for the table.
623702 //
624703 // By default, existing column metrics will be updated if they have changed.
0 commit comments