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? ';
|
||||
}
|
||||
|
||||
// ///
|
||||
// /// ## Writing a RenderSliver subclass
|
||||
// ///
|
||||
// /// ### Painting
|
||||
// ///
|
||||
// /// The [paint] method is called with an [Offset] to the top-left corner of the
|
||||
// /// sliver, _regardless of the axis direction_.
|
||||
// ///
|
||||
// /// ### childScrollOffset
|
||||
// ///
|
||||
// /// If the subclass positions children anywhere other than at scroll offset
|
||||
// /// 0.0, you need to override [childScrollOffset]...
|
||||
/// Base class for the render objects that implement scroll effects in viewports.
|
||||
///
|
||||
/// A [RenderViewport] has a list of child slivers. Each sliver — literally a
|
||||
/// 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
|
||||
/// those that have zero extent because they are "scrolled off" or are beyond
|
||||
/// the end of the viewport.)
|
||||
///
|
||||
/// Slivers participate in the _sliver protocol_, wherein during [layout] each
|
||||
/// sliver receives a [SliverConstraints] object and computes a corresponding
|
||||
/// [SliverGeometry] that describes where it fits in the viewport. This is
|
||||
/// 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 {
|
||||
// layout input
|
||||
@override
|
||||
@ -925,6 +1048,12 @@ abstract class RenderSliver extends RenderObject {
|
||||
/// vertical (i.e. the [SliverConstraints.axisDirection] is either
|
||||
/// [AxisDirection.right] or [AxisDirection.left]), then the
|
||||
/// `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 }) {
|
||||
if (mainAxisPosition >= 0.0 && mainAxisPosition < geometry.hitTestExtent &&
|
||||
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
|
||||
/// that is proportional to the [SliverConstraints.scrollOffset], then this
|
||||
/// 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 }) {
|
||||
assert(from <= to);
|
||||
final double a = constraints.scrollOffset;
|
||||
@ -1001,8 +1132,6 @@ abstract class RenderSliver extends RenderObject {
|
||||
/// [SliverConstraints.scrollOffset] and
|
||||
/// [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_
|
||||
/// 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
|
||||
@ -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
|
||||
/// 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
|
||||
/// [childMainAxisPosition] gives the distance from the leading _visible_ edge
|
||||
/// of the sliver whereas [childScrollOffset] gives the distance from sliver's
|
||||
/// zero scroll offset.
|
||||
/// of the sliver whereas [childScrollOffset] gives the distance from the
|
||||
/// sliver's zero scroll offset.
|
||||
///
|
||||
/// Calling this for a child that is not visible is not valid.
|
||||
@protected
|
||||
double childMainAxisPosition(covariant RenderObject child) {
|
||||
assert(() {
|
||||
@ -1027,13 +1154,16 @@ abstract class RenderSliver extends RenderObject {
|
||||
}
|
||||
|
||||
/// 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
|
||||
/// 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]
|
||||
/// 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.
|
||||
@protected
|
||||
@ -1062,6 +1192,8 @@ abstract class RenderSliver extends RenderObject {
|
||||
/// 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.
|
||||
/// This means that the dimensions may be negative.
|
||||
///
|
||||
/// This is only valid after [layout] has completed.
|
||||
@protected
|
||||
Size getAbsoluteSizeRelativeToOrigin() {
|
||||
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
|
||||
void handleEvent(PointerEvent event, SliverHitTestEntry entry) { }
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user