handleListObserve static method

ListViewObserveModel? handleListObserve({
  1. required BuildContext context,
  2. double fetchLeadingOffset()?,
  3. double? customOverlap(
    1. BuildContext
    )?,
  4. double toNextOverPercent = 1,
})

Handles observation logic of a sliver similar to SliverList.

Implementation

static ListViewObserveModel? handleListObserve({
  required BuildContext context,
  double Function()? fetchLeadingOffset,
  double? Function(BuildContext)? customOverlap,
  double toNextOverPercent = 1,
}) {
  var _obj = ObserverUtils.findRenderObject(context);
  if (_obj is! RenderSliverMultiBoxAdaptor) return null;
  final viewport = ObserverUtils.findViewport(_obj);
  if (viewport == null) return null;
  if (kDebugMode) {
    if (viewport.debugNeedsPaint) return null;
  }
  // The geometry.visible is not absolutely reliable.
  if (!(_obj.geometry?.visible ?? false) ||
      _obj.constraints.remainingPaintExtent < 1e-10) {
    return ListViewObserveModel(
      sliverList: _obj,
      viewport: viewport,
      visible: false,
      firstChild: null,
      displayingChildModelList: [],
    );
  }
  final scrollDirection = _obj.constraints.axis;
  var firstChild = _obj.firstChild;
  if (firstChild == null) return null;

  final offset = fetchLeadingOffset?.call() ?? 0;
  final overlap = customOverlap?.call(context) ?? _obj.constraints.overlap;
  final rawScrollViewOffset = _obj.constraints.scrollOffset + overlap;
  var scrollViewOffset = rawScrollViewOffset + offset;
  var parentData = firstChild.parentData as SliverMultiBoxAdaptorParentData;
  var index = parentData.index ?? 0;

  // Find out the first child which is displaying
  var targetFirstChild = firstChild;

  while (!ObserverUtils.isBelowOffsetWidgetInSliver(
    scrollViewOffset: scrollViewOffset,
    scrollDirection: scrollDirection,
    targetChild: targetFirstChild,
    toNextOverPercent: toNextOverPercent,
  )) {
    index = index + 1;
    var nextChild = _obj.childAfter(targetFirstChild);
    if (nextChild == null) break;

    if (nextChild is! RenderIndexedSemantics) {
      // It is separator
      nextChild = _obj.childAfter(nextChild);
    }
    if (nextChild == null) break;
    targetFirstChild = nextChild;
  }
  if (targetFirstChild is! RenderIndexedSemantics) return null;

  List<ListViewObserveDisplayingChildModel> displayingChildModelList = [
    ListViewObserveDisplayingChildModel(
      sliverList: _obj,
      viewport: viewport,
      index: targetFirstChild.index,
      renderObject: targetFirstChild,
    ),
  ];

  // Find the remaining children that are being displayed
  final showingChildrenMaxOffset =
      rawScrollViewOffset + _obj.constraints.remainingPaintExtent - overlap;
  var displayingChild = _obj.childAfter(targetFirstChild);
  while (ObserverUtils.isDisplayingChildInSliver(
    targetChild: displayingChild,
    showingChildrenMaxOffset: showingChildrenMaxOffset,
    scrollViewOffset: scrollViewOffset,
    scrollDirection: scrollDirection,
    toNextOverPercent: toNextOverPercent,
  )) {
    if (displayingChild == null) {
      break;
    }
    if (displayingChild is! RenderIndexedSemantics) {
      // It is separator
      displayingChild = _obj.childAfter(displayingChild);
      continue;
    }
    displayingChildModelList.add(ListViewObserveDisplayingChildModel(
      sliverList: _obj,
      viewport: viewport,
      index: displayingChild.index,
      renderObject: displayingChild,
    ));
    displayingChild = _obj.childAfter(displayingChild);
  }

  return ListViewObserveModel(
    sliverList: _obj,
    viewport: viewport,
    visible: true,
    firstChild: ListViewObserveDisplayingChildModel(
      sliverList: _obj,
      viewport: viewport,
      index: targetFirstChild.index,
      renderObject: targetFirstChild,
    ),
    displayingChildModelList: displayingChildModelList,
  );
}