hitTest method
Performs hit-testing at (localX, localY) in this object's coordinate
space. Adds matching entries to result, deepest first.
Returns true if this object or a descendant was hit.
Implementation
@override
bool hitTest(
HitTestResult result, {
required double localX,
required double localY,
}) {
if (localX < 0 ||
localY < 0 ||
localX >= size.width ||
localY >= size.height) {
return false;
}
final itemCount = _itemCount;
if (itemCount == 0) return false;
final separatorBreaks = _separatorBreaks(separator);
final offset = controller.offset.clamp(0, controller.maxOffset);
final contentY = localY + offset;
if (!variableHeight) {
final stride = math.max(1, itemExtent).toInt() + separatorBreaks;
final index = stride > 0 ? (contentY ~/ stride).toInt() : 0;
if (index < 0 || index >= itemCount) return false;
final childTop = (index * stride).toInt();
final childBottom = childTop + math.max(1, itemExtent).toInt();
if (contentY < childTop || contentY >= childBottom) return false;
final child = _childAt(index);
final childX = localX - child.offset.dx;
final childY = contentY - childTop - child.offset.dy;
return child.hitTest(result, localX: childX, localY: childY);
}
if (_lastPaintOffset == offset &&
_lastPaintViewportHeight == size.height.round() &&
_lastVisibleHits.isNotEmpty) {
final bufferY = localY.toInt() + _lastOffsetInItem;
for (final hit in _lastVisibleHits) {
if (bufferY >= hit.bufferStart && bufferY < hit.bufferEnd) {
final child = _childAt(hit.index);
final childX = localX - child.offset.dx;
final childY = bufferY - hit.bufferStart - child.offset.dy;
return child.hitTest(result, localX: childX, localY: childY);
}
}
}
// Variable-height hit testing favors correctness, with a Fenwick seed.
final estimate = math.max(1, estimatedItemExtent ?? itemExtent).toInt();
_syncCache(itemCount, separatorBreaks, estimate);
final resolved = debugResolveOffsetForContentOffset(contentY.toInt());
var i = resolved.index;
var top = _itemStartOffset(i);
while (i > 0 && top > contentY) {
i--;
top = _itemStartOffset(i);
}
for (; i < itemCount; i++) {
final childHeight = _resolveItemHeight(i, estimate);
final bottom = top + childHeight;
if (contentY >= top && contentY < bottom) {
final child = _childAt(i);
final childX = localX - child.offset.dx;
final childY = contentY - top - child.offset.dy;
return child.hitTest(result, localX: childX, localY: childY);
}
top = bottom;
if (i < itemCount - 1) {
final sepBottom = top + separatorBreaks;
if (contentY >= top && contentY < sepBottom) return false;
top = sepBottom;
}
}
return false;
}