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: [],
      displayingChildModelMap: {},
    );
  }
  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;

  // Whether the first child being displayed is not found.
  bool isNotFound = false;
  // 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) {
      isNotFound = true;
      break;
    }

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

  // The first child being displayed is not found, indicating that the
  // ScrollView is not visible.
  if (isNotFound) {
    return ListViewObserveModel(
      sliverList: _obj,
      viewport: viewport,
      visible: false,
      firstChild: null,
      displayingChildModelList: [],
      displayingChildModelMap: {},
    );
  }

  if (targetFirstChild is! RenderIndexedSemantics) return null;

  final firstDisplayingChildIndex = targetFirstChild.index;
  final firstDisplayingChildModel = ListViewObserveDisplayingChildModel(
    sliverList: _obj,
    viewport: viewport,
    index: firstDisplayingChildIndex,
    renderObject: targetFirstChild,
  );
  Map<int, ListViewObserveDisplayingChildModel> displayingChildModelMap = {
    firstDisplayingChildIndex: firstDisplayingChildModel,
  };
  List<ListViewObserveDisplayingChildModel> displayingChildModelList = [
    firstDisplayingChildModel,
  ];

  // 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;
    }

    final displayingChildIndex = displayingChild.index;
    final displayingChildModel = ListViewObserveDisplayingChildModel(
      sliverList: _obj,
      viewport: viewport,
      index: displayingChildIndex,
      renderObject: displayingChild,
    );
    displayingChildModelList.add(displayingChildModel);
    displayingChildModelMap[displayingChildIndex] = displayingChildModel;
    displayingChild = _obj.childAfter(displayingChild);
  }

  return ListViewObserveModel(
    sliverList: _obj,
    viewport: viewport,
    visible: true,
    firstChild: firstDisplayingChildModel,
    displayingChildModelList: displayingChildModelList,
    displayingChildModelMap: displayingChildModelMap,
  );
}