Add more dartdocs for the sliver render objects (#8749)

This patch covers multi-box adaptor and the viewports.
This commit is contained in:
Adam Barth 2017-03-13 22:57:05 +00:00 committed by GitHub
parent cb2b89c389
commit cbb495c16d
3 changed files with 177 additions and 33 deletions

View file

@ -1225,9 +1225,9 @@ abstract class RenderSliverHelpers implements RenderSliver {
///
/// See also:
///
/// - [RenderSliver], which explains more about the Sliver protocol.
/// - [RenderBox], which explains more about the Box protocol.
/// - [RenderViewport], which allows [RenderSliver] objects to be placed inside
/// * [RenderSliver], which explains more about the Sliver protocol.
/// * [RenderBox], which explains more about the Box protocol.
/// * [RenderViewport], which allows [RenderSliver] objects to be placed inside
/// a [RenderBox] (the opposite of this class).
class RenderSliverToBoxAdapter extends RenderSliver with RenderObjectWithChildMixin<RenderBox>, RenderSliverHelpers {
/// Creates a [RenderSliver] that wraps a [RenderBox].

View file

@ -75,6 +75,17 @@ abstract class RenderSliverBoxChildManager {
/// the child list after this function returns.
void didAdoptChild(RenderBox child);
/// Called during layout to indicate whether this object provided insufficient
/// children for the [RenderSliverMultiBoxAdaptor] to fill the
/// [SliverConstraints.remainingPaintExtent].
///
/// Typically called unconditionally at the start of layout with false and
/// then later called with true when the [RenderSliverMultiBoxAdaptor]
/// fails to create a child required to fill the
/// [SliverConstraints.remainingPaintExtent].
///
/// Useful for subclasses to determine whether newly added children could
/// affect the visible contents of the [RenderSliverMultiBoxAdaptor].
void setDidUnderflow(bool value);
/// In debug mode, asserts that this manager is not expecting any
@ -88,25 +99,47 @@ abstract class RenderSliverBoxChildManager {
bool debugAssertChildListLocked() => true;
}
/// Parent data structure used by [RenderSliverMultiBoxAdaptor].
class SliverMultiBoxAdaptorParentData extends SliverLogicalParentData with ContainerParentDataMixin<RenderBox> {
/// The index of this child according to the [RenderSliverBoxChildManager].
int index;
@override
String toString() => 'index=$index; ${super.toString()}';
}
// /// The contract for adding and removing children from this render object is
// /// more strict than for normal render objects:
// ///
// /// - Children can be removed except during a layout pass if they have already
// /// been laid out during that layout pass.
// /// - Children cannot be added except during a call to [childManager], and
// /// then only if there is no child correspending to that index (or the child
// /// child corresponding to that index was first removed).
/// A sliver with multiple box children.
///
/// [RenderSliverMultiBoxAdaptor] is a base class for slivers that have multiple
/// box children. The children are managed by a [RenderSliverBoxChildManager],
/// which lets subclasses create children lazily during layout. Typically
/// subclasses will create only those children that are actually needed to fill
/// the [SliverConstraints.remainingPaintExtent].
///
/// The contract for adding and removing children from this render object is
/// more strict than for normal render objects:
///
/// * Children can be removed except during a layout pass if they have already
/// been laid out during that layout pass.
/// * Children cannot be added except during a call to [childManager], and
/// then only if there is no child correspending to that index (or the child
/// child corresponding to that index was first removed).
///
/// See also:
///
/// * [RenderSliverToBoxAdapter], which has a single box child.
/// * [RenderSliverList], which places its children in a linear
/// array.
/// * [RenderSliverFixedExtentList], which places its children in a linear
/// array with a fixed extent in the main axis.
/// * [RenderSliverGrid], which places its children in arbitrary positions.
abstract class RenderSliverMultiBoxAdaptor extends RenderSliver
with ContainerRenderObjectMixin<RenderBox, SliverMultiBoxAdaptorParentData>,
RenderSliverHelpers {
/// Creates a sliver with multiple box children.
///
/// The [childManager] argument must not be null.
RenderSliverMultiBoxAdaptor({
@required RenderSliverBoxChildManager childManager
}) : _childManager = childManager {
@ -119,6 +152,12 @@ abstract class RenderSliverMultiBoxAdaptor extends RenderSliver
child.parentData = new SliverMultiBoxAdaptorParentData();
}
/// The delegate that manages the children of this object.
///
/// Rather than having a concrete list of children, a
/// [RenderSliverMultiBoxAdaptor] uses a [RenderSliverBoxChildManager] to
/// create children during layout in order to fill the
/// [SliverConstraints.remainingPaintExtent].
@protected
RenderSliverBoxChildManager get childManager => _childManager;
final RenderSliverBoxChildManager _childManager;
@ -379,6 +418,10 @@ abstract class RenderSliverMultiBoxAdaptor extends RenderSliver
}
}
/// Asserts that the reified child list is not empty and has a contiguous
/// sequence of indices.
///
/// Always returns true.
bool debugAssertChildListIsNonEmptyAndContiguous() {
assert(() {
assert(firstChild != null);

View file

@ -51,8 +51,6 @@ abstract class RenderAbstractViewport implements RenderObject {
double getOffsetToReveal(RenderObject target, double alignment);
}
typedef RenderSliver _Advancer(RenderSliver child);
// ///
// /// See also:
// ///
@ -72,6 +70,11 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix
assert(offset != null);
}
/// The direction in which the [scrollOffset] increases.
///
/// For example, if the [axisDirection] is [AxisDirection.down], a scroll
/// offset of zero is at the top of the viewport and increases towards the
/// bottom of the viewport.
AxisDirection get axisDirection => _axisDirection;
AxisDirection _axisDirection;
set axisDirection(AxisDirection value) {
@ -82,8 +85,18 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix
markNeedsLayout();
}
/// The axis along which the viewport scrolls.
///
/// For example, if the [axisDirection] is [AxisDirection.down], then the
/// [axis] is [Axis.vertical] and the viewport scrolls vertically.
Axis get axis => axisDirectionToAxis(axisDirection);
/// Which part of the content inside the viewport should be visible.
///
/// The [ViewportOffset.pixels] value determines the scroll offset that the
/// viewport uses to select which part of its content to display. As the user
/// scrolls the viewport, this value changes, which changes the content that
/// is displayed.
ViewportOffset get offset => _offset;
ViewportOffset _offset;
set offset(ViewportOffset value) {
@ -116,8 +129,38 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix
@override
bool get isRepaintBoundary => true;
/// Determines the size and position of some of the children of the viewport.
///
/// This function is the workhorse of `performLayout` implementations in
/// subclasses.
///
/// Layout starts with `child`, proceeds according to the `advance` callback,
/// and stops once `advance` returns null.
///
/// * `scrollOffset` is the [SliverConstraints.scrollOffset] to pass the
/// first child. The scroll offset is adjsted by
/// [SliverGeometry.scrollExtent] for subsequent children.
/// * `overlap` is the [SliverConstraints.overlap] to pass the first child.
/// The overlay is adjusted by the [SliverGeometry.paintOrigin] and
/// [SliverGeometry.paintExtent] for subsequent children.
/// * `layoutOffset` is the layout offset at which to place the first child.
/// The layout offset is updated by the [SliverGeometry.layoutExtent] for
/// subsequent children.
/// * `remainingPaintExtent` is [SliverConstraints.remainingPaintExtent] to
/// pass the first child. The remaining paint extent is updated by the
/// [SliverGeometry.layoutExtent] for subsequent children.
/// * `mainAxisExtent` is the [SliverConstraints.mainAxisExtent] to pass to
/// each child.
/// * `crossAxisExtent` is the [SliverConstraints.crossAxisExtent] to pass to
/// each child.
/// * `growthDirection` is the [SliverConstraints.growthDirection] to pass to
/// each child.
///
/// Returns the first non-zero [SliverGeometry.scrollOffsetCorrection]
/// encountered, if any. Otherwise returns 0.0. Typical callers will call this
/// function repeatedly until it returns 0.0.
@protected
double layoutOneSide(
double layoutChildSequence(
RenderSliver child,
double scrollOffset,
double overlap,
@ -126,7 +169,7 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix
double mainAxisExtent,
double crossAxisExtent,
GrowthDirection growthDirection,
_Advancer advance,
RenderSliver advance(RenderSliver child),
) {
assert(scrollOffset.isFinite);
assert(scrollOffset >= 0.0);
@ -166,7 +209,7 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix
if (scrollOffset <= 0.0)
scrollOffset = 0.0;
updateOutOfBoundsData(growthDirection, childLayoutGeometry);
updateOutOfBandData(growthDirection, childLayoutGeometry);
// move on to the next child
child = advance(child);
@ -181,14 +224,13 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix
if (firstChild == null)
return;
if (hasVisualOverflow) {
context.pushClipRect(needsCompositing, offset, Point.origin & size, paintContents);
context.pushClipRect(needsCompositing, offset, Point.origin & size, _paintContents);
} else {
paintContents(context, offset);
_paintContents(context, offset);
}
}
@protected
void paintContents(PaintingContext context, Offset offset) {
void _paintContents(PaintingContext context, Offset offset) {
for (RenderSliver child in childrenInPaintOrder) {
if (child.geometry.visible)
context.paintChild(child, offset + paintOffsetOf(child));
@ -330,6 +372,14 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix
return leadingScrollOffset - (mainAxisExtent - targetMainAxisExtent) * alignment;
}
/// The offset at which the given `child` should be painted.
///
/// The returned offset is from the top left corner of the inside of the
/// viewport to the top left corner of the paint coordinate system of the
/// `child`.
///
/// See also [paintOffsetOf], which uses the layout offset and growth
/// direction computed for the child during layout.
@protected
Offset computeAbsolutePaintOffset(RenderSliver child, double layoutOffset, GrowthDirection growthDirection) {
assert(hasSize); // this is only usable once we have a size
@ -363,7 +413,7 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix
String debugDescribeChildren(String prefix) {
if (firstChild == null)
return '$prefix\n';
int count = indexOfFirstChild();
int count = indexOfFirstChild;
String result = '$prefix \u2502\n';
RenderSliver child = firstChild;
while (child != lastChild) {
@ -382,22 +432,52 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix
// performLayout (and optionally sizedByParent and performResize)
/// Whether the contents of this viewport would paint outside the bounds of
/// the viewport if [paint] did not clip.
///
/// This property enables an optimization whereby [paint] can skip apply a
/// clip of the contents of the viewport are known to paint entirely within
/// the bounds of the viewport.
@protected
bool get hasVisualOverflow;
/// Called during [layoutChildSequence] for each child.
///
/// Typically used by subclasses to update any out-of-band data, such as the
/// max scroll extent, for each child.
@protected
void updateOutOfBoundsData(GrowthDirection growthDirection, SliverGeometry childLayoutGeometry);
void updateOutOfBandData(GrowthDirection growthDirection, SliverGeometry childLayoutGeometry);
/// Called during [layoutChildSequence] to store the layout offset for the
/// given child.
///
/// Different subclasses using different representations for their children's
/// layout offset (e.g., logical or physical coordinates). This function lets
/// subclasses transform the child's layout offset before storing it in the
/// child's parent data.
@protected
void updateChildLayoutOffset(RenderSliver child, double layoutOffset, GrowthDirection growthDirection);
/// The offset at which the given `child` should be painted.
///
/// The returned offset is from the top left corner of the inside of the
/// viewport to the top left corner of the paint coordinate system of the
/// `child`.
///
/// See also [computeAbsolutePaintOffset], which computes the paint offset
/// from an explict layout offset and growth direction instead of using the
/// values computed for the child during layout.
@protected
Offset paintOffsetOf(RenderSliver child);
/// Returns the scroll offset within the viewport for the given
/// `scrollOffsetWithinChild` within the given `child`.
///
/// The returned value is an estimate that assumes the slivers within the
/// viewport do not change the layout extent in response to changes in their
/// scroll offset.
@protected
double scrollOffsetOf(RenderSliver child, double scrollOffset);
// applyPaintTransform
double scrollOffsetOf(RenderSliver child, double scrollOffsetWithinChild);
/// Converts the `parentMainAxisPosition` into the child's coordinate system.
///
@ -418,9 +498,16 @@ abstract class RenderViewportBase<ParentDataClass extends ContainerParentDataMix
@protected
double computeChildMainAxisPosition(RenderSliver child, double parentMainAxisPosition);
/// The index of the first child of the viewport relative to the center child.
///
/// For example, the center child has index zero and the first child in the
/// reverse growth direction has index -1.
@protected
int indexOfFirstChild();
int get indexOfFirstChild;
/// A short string to identify the child with the given index.
///
/// Used by [debugDescribeChildren] to label the children.
@protected
String labelForChild(int index);
@ -478,6 +565,13 @@ class RenderViewport extends RenderViewportBase<SliverPhysicalContainerParentDat
child.parentData = new SliverPhysicalContainerParentData();
}
/// The relative position of the zero scroll offset.
///
/// For example, if [anchor] is 0.5 and the [axisDirection] is
/// [AxisDirection.down] or [AxisDirection.up], then the zero scroll offset is
/// vertically centered within the viewport. If the [anchor] is 1.0, and the
/// [axisDirection] is [AxisDirection.right], then the zero scroll offset is
/// on the left edge of the viewport.
double get anchor => _anchor;
double _anchor;
set anchor(double value) {
@ -489,6 +583,13 @@ class RenderViewport extends RenderViewportBase<SliverPhysicalContainerParentDat
markNeedsLayout();
}
/// The first child in the [GrowthDirection.forward] growth direction.
///
/// Children after [center] will be placed in the [axisDirection] relative to
/// the [center]. Children before [center] will be placed in the opposite of
/// the [axisDirection] relative to the [center].
///
/// The [center] must be a child of the viewport.
RenderSliver get center => _center;
RenderSliver _center;
set center(RenderSliver value) {
@ -673,7 +774,7 @@ class RenderViewport extends RenderViewportBase<SliverPhysicalContainerParentDat
if (leadingNegativeChild != null) {
// negative scroll offsets
final double result = layoutOneSide(
final double result = layoutChildSequence(
leadingNegativeChild,
math.max(mainAxisExtent, centerOffset) - mainAxisExtent,
0.0,
@ -689,7 +790,7 @@ class RenderViewport extends RenderViewportBase<SliverPhysicalContainerParentDat
}
// positive scroll offsets
return layoutOneSide(
return layoutChildSequence(
center,
math.max(0.0, -centerOffset),
leadingNegativeChild == null ? math.min(0.0, -centerOffset) : 0.0,
@ -706,7 +807,7 @@ class RenderViewport extends RenderViewportBase<SliverPhysicalContainerParentDat
bool get hasVisualOverflow => _hasVisualOverflow;
@override
void updateOutOfBoundsData(GrowthDirection growthDirection, SliverGeometry childLayoutGeometry) {
void updateOutOfBandData(GrowthDirection growthDirection, SliverGeometry childLayoutGeometry) {
switch (growthDirection) {
case GrowthDirection.forward:
_maxScrollExtent += childLayoutGeometry.scrollExtent;
@ -783,7 +884,7 @@ class RenderViewport extends RenderViewportBase<SliverPhysicalContainerParentDat
}
@override
int indexOfFirstChild() {
int get indexOfFirstChild {
assert(center != null);
assert(center.parent == this);
assert(firstChild != null);
@ -954,7 +1055,7 @@ class RenderShrinkWrappingViewport extends RenderViewportBase<SliverLogicalConta
_maxScrollExtent = 0.0;
_shrinkWrapExtent = 0.0;
_hasVisualOverflow = false;
return layoutOneSide(
return layoutChildSequence(
firstChild,
math.max(0.0, correctedOffset),
math.min(0.0, correctedOffset),
@ -971,7 +1072,7 @@ class RenderShrinkWrappingViewport extends RenderViewportBase<SliverLogicalConta
bool get hasVisualOverflow => _hasVisualOverflow;
@override
void updateOutOfBoundsData(GrowthDirection growthDirection, SliverGeometry childLayoutGeometry) {
void updateOutOfBandData(GrowthDirection growthDirection, SliverGeometry childLayoutGeometry) {
assert(growthDirection == GrowthDirection.forward);
_maxScrollExtent += childLayoutGeometry.scrollExtent;
if (childLayoutGeometry.hasVisualOverflow)
@ -1031,7 +1132,7 @@ class RenderShrinkWrappingViewport extends RenderViewportBase<SliverLogicalConta
}
@override
int indexOfFirstChild() => 0;
int get indexOfFirstChild => 0;
@override
String labelForChild(int index) => 'child $index';