handleObserveViewport method
To observe the viewport.
Implementation
SliverViewportObserveModel? handleObserveViewport({
bool isForceObserve = false,
bool isDependObserveCallback = true,
}) {
final isForbidObserveViewportCallback =
widget.sliverController?.isForbidObserveViewportCallback ?? false;
final onObserveViewport =
isForbidObserveViewportCallback ? null : widget.onObserveViewport;
if (isDependObserveCallback && onObserveViewport == null) return null;
final isHandlingScroll =
widget.sliverController?.innerIsHandlingScroll ?? false;
if (isHandlingScroll) return null;
final ctxs = fetchTargetSliverContexts();
final objList = ctxs.map((e) => ObserverUtils.findRenderObject(e)).toList();
if (objList.isEmpty) return null;
final firstObj = objList.first;
if (firstObj == null) return null;
final viewport = ObserverUtils.findViewport(firstObj);
if (viewport == null) return null;
final viewportOffset = viewport.offset;
if (viewportOffset is! ScrollPosition) return null;
var targetChild = viewport.firstChild;
if (targetChild == null) return null;
var offset = widget.leadingOffset;
if (widget.dynamicLeadingOffset != null) {
offset = widget.dynamicLeadingOffset!();
}
final pixels = viewportOffset.pixels;
final startCalcPixels = pixels + offset;
int indexOfTargetChild = objList.indexOf(targetChild);
// Find out the first sliver which is displayed in viewport.
final dimension = viewportOffset.viewportDimension;
final viewportBottomOffset = pixels + dimension;
while (!ObserverUtils.isValidListIndex(indexOfTargetChild) ||
!ObserverUtils.isDisplayingSliverInViewport(
sliver: targetChild,
viewportPixels: startCalcPixels,
viewportBottomOffset: viewportBottomOffset,
)) {
if (targetChild == null) break;
final nextChild = viewport.childAfter(targetChild);
if (nextChild == null) break;
targetChild = nextChild;
indexOfTargetChild = objList.indexOf(targetChild);
}
if (targetChild == null ||
!ObserverUtils.isValidListIndex(indexOfTargetChild)) return null;
final targetCtx = ctxs[indexOfTargetChild];
final firstChild = SliverViewportObserveDisplayingChildModel(
sliverContext: targetCtx,
sliver: targetChild,
);
List<SliverViewportObserveDisplayingChildModel> displayingChildModelList = [
firstChild
];
// Find the remaining children that are being displayed.
targetChild = viewport.childAfter(targetChild);
while (targetChild != null) {
// The current targetChild is not displayed, so the later children don't
// need to be check
if (!ObserverUtils.isDisplayingSliverInViewport(
sliver: targetChild,
viewportPixels: startCalcPixels,
viewportBottomOffset: viewportBottomOffset,
)) break;
indexOfTargetChild = objList.indexOf(targetChild);
if (ObserverUtils.isValidListIndex(indexOfTargetChild)) {
// The current targetChild is target.
final context = ctxs[indexOfTargetChild];
displayingChildModelList.add(SliverViewportObserveDisplayingChildModel(
sliverContext: context,
sliver: targetChild,
));
}
// continue to check next child.
targetChild = viewport.childAfter(targetChild);
}
var model = SliverViewportObserveModel(
viewport: viewport,
firstChild: firstChild,
displayingChildModelList: displayingChildModelList,
);
bool canReturnResult = false;
if (isForceObserve ||
widget.triggerOnObserveType == ObserverTriggerOnObserveType.directly) {
canReturnResult = true;
} else if (model != lastViewportObserveResultModel) {
canReturnResult = true;
}
if (canReturnResult &&
isDependObserveCallback &&
onObserveViewport != null) {
onObserveViewport(model);
}
// Record it for the next comparison.
lastViewportObserveResultModel = model;
return canReturnResult ? model : null;
}