ViewportOffsetis an interface that tracks the current scroll offset (
ViewportOffset.pixels) and direction (
ViewportOffset.userScrollDirection, which is relative to the positive axis direction, ignoring growth direction); it also offers a variety of helpers (e.g.,
ViewportOffset.animateTo). The offset represents how much content has been scrolled off screen, or more precisely, the number of logical pixels by which all children have been shifted opposite the viewport’s scrolling direction (
Viewport.axisDirection). For a web page, this would be how many pixels of content are above the browser’s viewport. This interface is implemented by
ScrollPosition, tying together viewports and scrollables. Pixels can be negative when scrolling before the center sliver. [?]
Viewportis a layout widget that is larger on the inside. The viewport is associated with a scroll offset (
ViewportOffset), an interface that is implemented by
ScrollPositionand typically fulfilled by
ScrollPositionWithSingleContext. As the user scrolls, this offset is propagated to descendant slivers via layout. Finally, slivers are repainted at their new offsets, creating the visual effect of scrolling.
ShrinkWrappingViewportis a variant of viewport that sizes itself to match its children in the main axis (instead of expanding to fill the main axis).
NestedScrollViewViewportis a specialized viewport used by
NestedScrollViewto coordinate scrolling across two viewports (supported by auxiliary widgets like
ScrollViewcouples a viewport with a scrollable, delegating to its subclass to provide slivers; as such, the
ScrollViewprovides a foundation for building scrollable UI.
CustomScrollViewaccepts an arbitrary sliver list whereas
BoxScrollView-- and its subclasses
GridView-- apply a single layout model (e.g., list or grid) to a collection of slivers.
RenderAbstractViewportprovides a common interface for all viewport subtypes. This allows the framework to locate and interact with viewports in a generic way (via
RenderAbstractViewport.of). It also provides a generic interface for determining offsets necessary to reveal certain children.
RenderViewportBaseprovides shared code for render objects that host slivers. By establishing an axis and axis direction,
RenderViewportBasemaps the offset-based coordinate space used by slivers into cartesian space according to a managed offset value (
RenderViewportBase.layoutChildSequenceserves as the foundation for sliver layout (and is typically invoked by
RenderViewportBasealso establishes the cache extent (the area to either side of the viewport that is laid out but not visible) as well as entry points for hit testing and painting.
RenderViewportdisplays a subset of its sliver children based on its current viewport offset. A center sliver (
RenderViewport.center) is anchored at offset zero. Slivers before center (“reverse children”) grow opposite the axis direction (
GrowthDirection.reverse) whereas the center along with subsequent slivers (“forward children”) grow forward (
GrowthDirection.forward); both groups are anchored according to the same axis direction (this is why both start from the same edge), though conceptually reverse slivers are laid out in the opposite axis direction (e.g., their “leading” and “trailing” edges are flipped).
RenderViewport.anchoris in the range [0, 1], with zero corresponding to the axis origin [?]).
RenderViewportexcept sized to match the total extent of visible children within the bounds of incoming constraints.
GrowthDirection.forward). “Reverse slivers” immediately precede the center sliver and are laid out opposite the axis direction (
GrowthDirection.reverse). The line between forward and reverse slivers, at the center sliver’s leading edge, is called the “centerline,” coincident with the zero scroll offset. Within this document, the region within the viewport comprised of reverse slivers is called the “reverse region” with its counterpart being the “forward region.”
Notethat the viewport’s inner edges fully encompass both regions.
RenderViewport.offset) to determine which of its sliver children are in view and therefore should be rendered. This offset represents the distance between the center sliver’s leading edge (i.e., scroll offset zero) and the viewport’s outer leading edge, and increases opposite the axis direction.
RenderShrinkWrappingViewport). These differ in how they represent the child’s position. The former stores absolute coordinates from the parent’s visible top left corner whereas the latter stores the distance from the parent’s zero scroll offset to the child’s nearest edge. Physical coordinates are more efficient for children that must repaint often but incur a cost during layout. Logical coordinates optimize layout at the expense of added cost during painting.
SliverLogicalContainerParentData. These are identical to their superclasses (where the “parent” isn’t a sliver but the viewport itself), mixing in
RenderSliver.centerOffsetAdjustment(added to the current
ViewportOffset.pixelsvalue). This effectively shifts the zero scroll offset (e.g., to visually center the center sliver).
RenderViewport.anchor. Zero positions the zero offset at the viewport’s leading edge; one positions the offset at the trailing edge (and
0.5would position it at the midpoint).
RenderViewport._attemptLayout). Conceptually, it is easiest to ignore them other than to know that they shift the centerline’s visual position.
SliverGeometry.paintOrigin, though this won’t actually move the zero offset.
SliverConstraints.axisDirection), though reverse sliver calculations (e.g., for painting or layout offset) effectively flip this direction. Thus, it is most intuitive to think of reverse slivers as having their leading and trailing edges flipped, etc.
RenderViewportBase.layoutChildSequence) and these extents are zero unless a sliver is visible, this formal definition boils down to the practical definition described above. [?]
RenderViewportBase.computeAbsolutePaintOffsetis able to produce paint offsets trivially from layout offsets (this is surprising since layout offsets are ostensibly measured from the zero scroll offset whereas paint offsets are measured from the box’s top left corner).
RenderViewportBase.layoutChildSequence), this direct mapping remains safe as out-of-bounds painting will be clipped.
RenderViewportBase.maxScrollObstructionExtentBefore), a region of the viewport that is covered by “pinned” slivers and that effectively reduces the viewport’s scrollable bounds. This is a secondary concept used only when computing the scroll offset to reveal a certain sliver (
SliverPhysicalContainerParentData, allowing paint offsets to be returned immediately).
RenderViewport.firstChild) is the “last” reverse sliver.
ViewportOffset.pixelsvalue allowing descendent slivers to adjust the overall scrolling position. This is done to account for errors when estimating overall scroll extent for slivers that build content dynamically.
ViewportOffset.pixels, translating content opposite the viewport’s axis direction -- i.e., scrolling forward).
SliverList); thus, when such a sliver requests a scroll offset correction, the offset selected is one that would cause any existing, unaltered state to be consistent.
SliverListmay not have enough room for newly revealed children when scrolling backwards (e.g., because the incoming scroll offset indicates an inadequate number of pixels preceding the viewport’s leading edge). The
SliverListcalculates the scroll offset correction that would have avoided this logical inconsistency, adjusting it (and any affected layout offsets) to ensure that children appear at the same visual location in the viewport.