Add some documentation for RenderSliver. (#10272)
This commit is contained in:
parent
51ba6b377b
commit
f53d0fece2
@ -763,18 +763,141 @@ String _debugCompareFloats(String labelA, double valueA, String labelB, double v
|
|||||||
'apply the min() or max() functions, or the clamp() method, to the $labelB? ';
|
'apply the min() or max() functions, or the clamp() method, to the $labelB? ';
|
||||||
}
|
}
|
||||||
|
|
||||||
// ///
|
/// Base class for the render objects that implement scroll effects in viewports.
|
||||||
// /// ## Writing a RenderSliver subclass
|
///
|
||||||
// ///
|
/// A [RenderViewport] has a list of child slivers. Each sliver — literally a
|
||||||
// /// ### Painting
|
/// slice of the viewport's contents — is laid out in turn, covering the
|
||||||
// ///
|
/// viewport in the process. (Every sliver is laid out each time, including
|
||||||
// /// The [paint] method is called with an [Offset] to the top-left corner of the
|
/// those that have zero extent because they are "scrolled off" or are beyond
|
||||||
// /// sliver, _regardless of the axis direction_.
|
/// the end of the viewport.)
|
||||||
// ///
|
///
|
||||||
// /// ### childScrollOffset
|
/// Slivers participate in the _sliver protocol_, wherein during [layout] each
|
||||||
// ///
|
/// sliver receives a [SliverConstraints] object and computes a corresponding
|
||||||
// /// If the subclass positions children anywhere other than at scroll offset
|
/// [SliverGeometry] that describes where it fits in the viewport. This is
|
||||||
// /// 0.0, you need to override [childScrollOffset]...
|
/// analogous to the box protocol used by [RenderBox], which gets a
|
||||||
|
/// [BoxConstraints] as input and computes a [Size].
|
||||||
|
///
|
||||||
|
/// Slivers have a leading edge, which is where the position described by
|
||||||
|
/// [SliverConstraints.scrollOffset] for this sliver begins. Slivers have
|
||||||
|
/// several dimensions, the primary of which is [SliverGeometry.paintExtent],
|
||||||
|
/// which describes the extent of the sliver along the main axis, starting from
|
||||||
|
/// the leading edge, reaching either the end of the viewport or the end of the
|
||||||
|
/// sliver, whichever comes first.
|
||||||
|
///
|
||||||
|
/// Slivers can change dimensions based on the changing constraints in a
|
||||||
|
/// non-linear fashion, to achieve various scroll effects. For example, the
|
||||||
|
/// various [RenderSliverPersistentHeader] subclasses, on which [SliverAppBar]
|
||||||
|
/// is based, achieve effects such as staying visible despite the scroll offset,
|
||||||
|
/// or reappearing at different offsets based on the user's scroll direction
|
||||||
|
/// ([SliverConstraints.userScrollDirection]).
|
||||||
|
///
|
||||||
|
/// ## Writing a RenderSliver subclass
|
||||||
|
///
|
||||||
|
/// Slivers can have sliver children, or children from another coordinate
|
||||||
|
/// system, typically box children. (For details on the box protocol, see
|
||||||
|
/// [RenderBox].) Slivers can also have different child models, typically having
|
||||||
|
/// either one child, or a list of children.
|
||||||
|
///
|
||||||
|
/// ### Examples of slivers
|
||||||
|
///
|
||||||
|
/// A good example of a sliver with a single child that is also itself a sliver
|
||||||
|
/// is [RenderSliverPadding], which indents its child. A sliver-to-sliver render
|
||||||
|
/// object such as this must construct a [SliverConstraints] object for its
|
||||||
|
/// child, then must take its child's [SliverGeometry] and use it to form its
|
||||||
|
/// own [geometry].
|
||||||
|
///
|
||||||
|
/// The other common kind of one-child sliver is a sliver that has a single
|
||||||
|
/// [RenderBox] child. An example of that would be [RenderSliverToBoxAdapter],
|
||||||
|
/// which lays out a single box and sizes itself around the box. Such a sliver
|
||||||
|
/// must use its [SliverConstraints] to create a [BoxConstraints] for the
|
||||||
|
/// child, lay the child out (using the child's [layout] method), and then use
|
||||||
|
/// the child's [RenderBox.size] to generate the sliver's [SliverGeometry].
|
||||||
|
///
|
||||||
|
/// The most common kind of sliver though is one with multiple children. The
|
||||||
|
/// most straight-forward example of this is [RenderSliverList], which arranges
|
||||||
|
/// its children one after the other in the main axis direction. As with the
|
||||||
|
/// one-box-child sliver case, it uses its [constraints] to create a
|
||||||
|
/// [BoxConstraints] for the children, and then it uses the aggregate
|
||||||
|
/// information from all its children to generate its [geometry]. Unlike the
|
||||||
|
/// one-child cases, however, it is judicious in which children it actually lays
|
||||||
|
/// out (and later paints). If the scroll offset is 1000 pixels, and it
|
||||||
|
/// previously determined that the first three children are each 400 pixels
|
||||||
|
/// tall, then it will skip the first two and start the layout with its third
|
||||||
|
/// child.
|
||||||
|
///
|
||||||
|
/// ### Layout
|
||||||
|
///
|
||||||
|
/// As they are laid out, slivers decide their [geometry], which includes their
|
||||||
|
/// size ([SliverGeometry.paintExtent]) and the position of the next sliver
|
||||||
|
/// ([SliverGeometry.layoutExtent]), as well as the position of each of their
|
||||||
|
/// children, based on the input [constraints] from the viewport such as the
|
||||||
|
/// scroll offset ([SliverConstraints.scrollOffset]).
|
||||||
|
///
|
||||||
|
/// For example, a sliver that just paints a box 100 pixels high would say its
|
||||||
|
/// [SliverGeometry.paintExtent] was 100 pixels when the scroll offset was zero,
|
||||||
|
/// but would say its [SliverGeometry.paintExtent] was 25 pixels when the scroll
|
||||||
|
/// offset was 75 pixels, and would say it was zero when the scroll offset was
|
||||||
|
/// 100 pixels or more. (This is assuming that
|
||||||
|
/// [SliverConstraints.remainingPaintExtent] was more than 100 pixels.)
|
||||||
|
///
|
||||||
|
/// The various dimensions that are provided as input to this system are in the
|
||||||
|
/// [constraints]. They are described in detail in the documentation for the
|
||||||
|
/// [SliverConstraints] class.
|
||||||
|
///
|
||||||
|
/// The [performLayout] function must take these [constraints] and create a
|
||||||
|
/// [SliverGeometry] object that it must then assign to the [geometry] property.
|
||||||
|
/// The different dimensions of the geometry that can be configured are
|
||||||
|
/// described in detail in the documentation for the [SliverGeometry] class.
|
||||||
|
///
|
||||||
|
/// ### Painting
|
||||||
|
///
|
||||||
|
/// In addition to implementing layout, a sliver must also implement painting.
|
||||||
|
/// This is achieved by overriding the [paint] method.
|
||||||
|
///
|
||||||
|
/// The [paint] method is called with an [Offset] from the [Canvas] origin to
|
||||||
|
/// the top-left corner of the sliver, _regardless of the axis direction_.
|
||||||
|
///
|
||||||
|
/// Subclasses should also override [applyPaintTransform] to provide the
|
||||||
|
/// [Matrix4] describing the position of each child relative to the sliver.
|
||||||
|
/// (This is used by, among other things, the accessibility layer, to determine
|
||||||
|
/// the bounds of the child.)
|
||||||
|
///
|
||||||
|
/// ### Hit testing
|
||||||
|
///
|
||||||
|
/// To implement hit testing, either override the [hitTestSelf] and
|
||||||
|
/// [hitTestChildren] methods, or, for more complex cases, instead override the
|
||||||
|
/// [hitTest] method directly.
|
||||||
|
///
|
||||||
|
/// To actually react to pointer events, the [handleEvent] method may be
|
||||||
|
/// implemented. By default it does nothing. (Typically gestures are handled by
|
||||||
|
/// widgets in the box protocol, not by slivers directly.)
|
||||||
|
///
|
||||||
|
/// ### Helper methods
|
||||||
|
///
|
||||||
|
/// There are a number of methods that a sliver should implement which will make
|
||||||
|
/// the other methods easier to implement. Each method listed below has detailed
|
||||||
|
/// documentation. In addition, the [RenderSliverHelpers] class can be used to
|
||||||
|
/// mix in some helpful methods.
|
||||||
|
///
|
||||||
|
/// #### childScrollOffset
|
||||||
|
///
|
||||||
|
/// If the subclass positions children anywhere other than at scroll offset
|
||||||
|
/// zero, it should override [childScrollOffset]. For example,
|
||||||
|
/// [RenderSliverList] and [RenderSliverGrid] override this method, but
|
||||||
|
/// [RenderSliverToBoxAdapter] does not.
|
||||||
|
///
|
||||||
|
/// This is used by, among other things, [Scrollable.ensureVisible].
|
||||||
|
///
|
||||||
|
/// #### childMainAxisPosition
|
||||||
|
///
|
||||||
|
/// Subclasses should implement [childMainAxisPosition] to describe where their
|
||||||
|
/// children are positioned.
|
||||||
|
///
|
||||||
|
/// #### childCrossAxisPosition
|
||||||
|
///
|
||||||
|
/// If the subclass positions children in the cross-axis at a position other
|
||||||
|
/// than zero, then it should override [childCrossAxisPosition]. For example
|
||||||
|
/// [RenderSliverGrid] overrides this method.
|
||||||
abstract class RenderSliver extends RenderObject {
|
abstract class RenderSliver extends RenderObject {
|
||||||
// layout input
|
// layout input
|
||||||
@override
|
@override
|
||||||
@ -925,6 +1048,12 @@ abstract class RenderSliver extends RenderObject {
|
|||||||
/// vertical (i.e. the [SliverConstraints.axisDirection] is either
|
/// vertical (i.e. the [SliverConstraints.axisDirection] is either
|
||||||
/// [AxisDirection.right] or [AxisDirection.left]), then the
|
/// [AxisDirection.right] or [AxisDirection.left]), then the
|
||||||
/// `crossAxisPosition` is a distance from the top edge of the sliver.
|
/// `crossAxisPosition` is a distance from the top edge of the sliver.
|
||||||
|
///
|
||||||
|
/// ## Implementing hit testing for slivers
|
||||||
|
///
|
||||||
|
/// The most straight-forward way to implement hit testing for a new sliver
|
||||||
|
/// render object is to override its [hitTestSelf] and [hitTestChildren]
|
||||||
|
/// methods.
|
||||||
bool hitTest(HitTestResult result, { @required double mainAxisPosition, @required double crossAxisPosition }) {
|
bool hitTest(HitTestResult result, { @required double mainAxisPosition, @required double crossAxisPosition }) {
|
||||||
if (mainAxisPosition >= 0.0 && mainAxisPosition < geometry.hitTestExtent &&
|
if (mainAxisPosition >= 0.0 && mainAxisPosition < geometry.hitTestExtent &&
|
||||||
crossAxisPosition >= 0.0 && crossAxisPosition < constraints.crossAxisExtent) {
|
crossAxisPosition >= 0.0 && crossAxisPosition < constraints.crossAxisExtent) {
|
||||||
@ -980,6 +1109,8 @@ abstract class RenderSliver extends RenderObject {
|
|||||||
/// sliver always paints the same amount but consumes a scroll offset extent
|
/// sliver always paints the same amount but consumes a scroll offset extent
|
||||||
/// that is proportional to the [SliverConstraints.scrollOffset], then this
|
/// that is proportional to the [SliverConstraints.scrollOffset], then this
|
||||||
/// function's results will not be consistent.
|
/// function's results will not be consistent.
|
||||||
|
// This could be a static method but isn't, because it would be less convenient
|
||||||
|
// to call it from subclasses if it was.
|
||||||
double calculatePaintOffset(SliverConstraints constraints, { @required double from, @required double to }) {
|
double calculatePaintOffset(SliverConstraints constraints, { @required double from, @required double to }) {
|
||||||
assert(from <= to);
|
assert(from <= to);
|
||||||
final double a = constraints.scrollOffset;
|
final double a = constraints.scrollOffset;
|
||||||
@ -1001,8 +1132,6 @@ abstract class RenderSliver extends RenderObject {
|
|||||||
/// [SliverConstraints.scrollOffset] and
|
/// [SliverConstraints.scrollOffset] and
|
||||||
/// [SliverLogicalParentData.layoutOffset].
|
/// [SliverLogicalParentData.layoutOffset].
|
||||||
///
|
///
|
||||||
/// Calling this for a child that is not visible is not valid.
|
|
||||||
///
|
|
||||||
/// For children that are [RenderSliver]s, the leading edge of the _child_
|
/// For children that are [RenderSliver]s, the leading edge of the _child_
|
||||||
/// will be the leading _visible_ edge of the child, not the part of the child
|
/// will be the leading _visible_ edge of the child, not the part of the child
|
||||||
/// that would locally be a scroll offset 0.0. For children that are not
|
/// that would locally be a scroll offset 0.0. For children that are not
|
||||||
@ -1010,14 +1139,12 @@ abstract class RenderSliver extends RenderObject {
|
|||||||
/// to the edge of the box, since those boxes do not know how to handle being
|
/// to the edge of the box, since those boxes do not know how to handle being
|
||||||
/// scrolled.
|
/// scrolled.
|
||||||
///
|
///
|
||||||
/// This is used by [RenderSliverHelpers.hitTestBoxChild]. If you do not use
|
|
||||||
/// the [RenderSliverHelpers] mixin and do not call this method yourself, you
|
|
||||||
/// do not need to implement this method.
|
|
||||||
///
|
|
||||||
/// This method differs from [childScrollOffset] in that
|
/// This method differs from [childScrollOffset] in that
|
||||||
/// [childMainAxisPosition] gives the distance from the leading _visible_ edge
|
/// [childMainAxisPosition] gives the distance from the leading _visible_ edge
|
||||||
/// of the sliver whereas [childScrollOffset] gives the distance from sliver's
|
/// of the sliver whereas [childScrollOffset] gives the distance from the
|
||||||
/// zero scroll offset.
|
/// sliver's zero scroll offset.
|
||||||
|
///
|
||||||
|
/// Calling this for a child that is not visible is not valid.
|
||||||
@protected
|
@protected
|
||||||
double childMainAxisPosition(covariant RenderObject child) {
|
double childMainAxisPosition(covariant RenderObject child) {
|
||||||
assert(() {
|
assert(() {
|
||||||
@ -1027,13 +1154,16 @@ abstract class RenderSliver extends RenderObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the distance along the cross axis from the zero of the cross axis
|
/// Returns the distance along the cross axis from the zero of the cross axis
|
||||||
/// to the nearest side of the given child.
|
/// in this sliver's [paint] coordinate space to the nearest side of the given
|
||||||
|
/// child.
|
||||||
///
|
///
|
||||||
/// For example, if the [constraints] describe this sliver as having an axis
|
/// For example, if the [constraints] describe this sliver as having an axis
|
||||||
/// direction of [AxisDirection.down], then this is the distance from the left
|
/// direction of [AxisDirection.down], then this is the distance from the left
|
||||||
/// of the sliver to the left of the child. Similarly, if the [constraints]
|
/// of the sliver to the left of the child. Similarly, if the [constraints]
|
||||||
/// describe this sliver as having an axis direction of [AxisDirection.up],
|
/// describe this sliver as having an axis direction of [AxisDirection.up],
|
||||||
/// then this is value is the same.
|
/// then this is value is the same. If the axis direction is
|
||||||
|
/// [AxisDirection.left] or [AxisDirection.right], then it is the distance
|
||||||
|
/// from the top of the sliver to the top of the child.
|
||||||
///
|
///
|
||||||
/// Calling this for a child that is not visible is not valid.
|
/// Calling this for a child that is not visible is not valid.
|
||||||
@protected
|
@protected
|
||||||
@ -1062,6 +1192,8 @@ abstract class RenderSliver extends RenderObject {
|
|||||||
/// This returns a [Size] with dimensions relative to the leading edge of the
|
/// This returns a [Size] with dimensions relative to the leading edge of the
|
||||||
/// sliver, specifically the same offset that is given to the [paint] method.
|
/// sliver, specifically the same offset that is given to the [paint] method.
|
||||||
/// This means that the dimensions may be negative.
|
/// This means that the dimensions may be negative.
|
||||||
|
///
|
||||||
|
/// This is only valid after [layout] has completed.
|
||||||
@protected
|
@protected
|
||||||
Size getAbsoluteSizeRelativeToOrigin() {
|
Size getAbsoluteSizeRelativeToOrigin() {
|
||||||
assert(geometry != null);
|
assert(geometry != null);
|
||||||
@ -1183,6 +1315,7 @@ abstract class RenderSliver extends RenderObject {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This override exists only to change the type of the second argument.
|
||||||
@override
|
@override
|
||||||
void handleEvent(PointerEvent event, SliverHitTestEntry entry) { }
|
void handleEvent(PointerEvent event, SliverHitTestEntry entry) { }
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user