computeStickyHeaders method
void
computeStickyHeaders({
- required double scrollOffset,
- required double overlap,
- required List<
TKey> visibleNodes, - required Float64List nodeOffsetsByNid,
- required Float64List nodeExtentsByNid,
- required FindFirstVisibleIndex findFirstVisibleIndex,
Computes sticky headers based on scroll position, populating
headers and the per-nid lookup. Called after Pass 2 when actual
extents and offsets are available. overlap is constraints.overlap
— the number of pixels at the top covered by a preceding pinned
sliver (e.g. PinnedHeaderSliver).
Implementation
void computeStickyHeaders({
required double scrollOffset,
required double overlap,
required List<TKey> visibleNodes,
required Float64List nodeOffsetsByNid,
required Float64List nodeExtentsByNid,
required FindFirstVisibleIndex findFirstVisibleIndex,
}) {
// Null out prior-layout sticky entries before recomputing. Iterate
// [_writtenStickyNids] (the nids we wrote LAST frame) instead of
// resolving keys back to nids — a key that was freed since last
// layout (immediate-purge removal) would yield `noNid`, leaving the
// stale entry to leak stickiness onto whichever fresh key recycles
// the nid. The nid handle is stable until reallocation, so clearing
// through it is correct even when the original occupant is gone.
for (int i = 0; i < _writtenStickyNidsLen; i++) {
final nid = _writtenStickyNids[i];
if (nid >= 0 && nid < _stickyByNid.length) {
_stickyByNid[nid] = null;
}
}
_writtenStickyNidsLen = 0;
_stickyHeaders.clear();
double? parentPinnedY;
_forEachStickyCandidate(
scrollOffset: scrollOffset,
overlap: overlap,
visibleNodes: visibleNodes,
nodeOffsetsByNid: nodeOffsetsByNid,
nodeExtentsByNid: nodeExtentsByNid,
findFirstVisibleIndex: findFirstVisibleIndex,
onCandidate: (candidateId, pinnedY, extent, stackTop) {
// Deeper headers can slide behind parent, but must never go above
// parent TOP.
if (parentPinnedY != null) {
pinnedY = math.max(parentPinnedY!, pinnedY);
if (pinnedY + extent <= stackTop) return false;
}
final indent = _controller.getIndent(candidateId);
final info = StickyHeaderInfo<TKey>(
nodeId: candidateId,
pinnedY: pinnedY,
extent: extent,
indent: indent,
);
_stickyHeaders.add(info);
final nid = _controller.nidOf(candidateId);
_stickyByNid[nid] = info;
if (_writtenStickyNidsLen == _writtenStickyNids.length) {
final grown = Int32List(_writtenStickyNids.length * 2);
grown.setRange(0, _writtenStickyNidsLen, _writtenStickyNids);
_writtenStickyNids = grown;
}
_writtenStickyNids[_writtenStickyNidsLen++] = nid;
parentPinnedY = pinnedY;
return true;
},
);
_lastStickyScrollOffset = scrollOffset;
}