Commit fecc4e65 authored by Adam Barth's avatar Adam Barth Committed by GitHub

Docs for RenderSliverFixedExtentList (#8733)

Also, some renames for more accuracy.
parent 8742fb09
...@@ -10,7 +10,33 @@ import 'box.dart'; ...@@ -10,7 +10,33 @@ import 'box.dart';
import 'sliver.dart'; import 'sliver.dart';
import 'sliver_multi_box_adaptor.dart'; import 'sliver_multi_box_adaptor.dart';
/// A sliver that contains multiple box children that have the same extent in
/// the main axis.
///
/// [RenderSliverFixedExtentBoxAdaptor] places its children in a linear array
/// along the main axis. Each child is forced to have the [itemExtent] in the
/// main axis and the [SliverConstraints.crossAxisExtent] in the cross axis.
///
/// Subclasses should override [itemExtent] to control the size of the children
/// in the main axis. For a concrete subclass with a configurable [itemExtent],
/// see [RenderSliverFixedExtentList].
///
/// [RenderSliverFixedExtentBoxAdaptor] is more efficient than
/// [RenderSliverList] because [RenderSliverFixedExtentBoxAdaptor] does not need
/// to perform layout on its children to obtain their extent in the main axis.
///
/// See also:
///
/// * [RenderSliverFixedExtentList], which has a configurable [itemExtent].
/// * [RenderSliverFill], which determines the [itemExtent] based on
/// [SliverConstraints.viewportMainAxisExtent].
/// * [RenderSliverList], which does not require its children to have the same
/// extent in the main axis.
abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAdaptor { abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAdaptor {
/// Creates a sliver that contains multiple box children that have the same
/// extent in the main axis.
///
/// The [childManager] argument must not be null.
RenderSliverFixedExtentBoxAdaptor({ RenderSliverFixedExtentBoxAdaptor({
@required RenderSliverBoxChildManager childManager, @required RenderSliverBoxChildManager childManager,
}) : super(childManager: childManager); }) : super(childManager: childManager);
...@@ -18,19 +44,47 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda ...@@ -18,19 +44,47 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda
/// The main-axis extent of each item. /// The main-axis extent of each item.
double get itemExtent; double get itemExtent;
/// The layout offset for the child with the given index.
///
/// This function is given the [itemExtent] as an argument to avoid
/// recomputing [itemExtent] repeatedly during layout.
///
/// By default, places the children in order, without gaps, starting from
/// layout offset zero.
@protected @protected
double indexToScrollOffset(double itemExtent, int index) => itemExtent * index; double indexToLayoutOffset(double itemExtent, int index) => itemExtent * index;
/// The minimum child index that is visible at the given scroll offset.
///
/// This function is given the [itemExtent] as an argument to avoid
/// recomputing [itemExtent] repeatedly during layout.
///
/// By default, returns a value consistent with the children being placed in
/// order, without gaps, starting from layout offset zero.
@protected @protected
int getMinChildIndexForScrollOffset(double scrollOffset, double itemExtent) { int getMinChildIndexForScrollOffset(double scrollOffset, double itemExtent) {
return itemExtent > 0.0 ? math.max(0, scrollOffset ~/ itemExtent) : 0; return itemExtent > 0.0 ? math.max(0, scrollOffset ~/ itemExtent) : 0;
} }
/// The maximum child index that is visible at the given scroll offset.
///
/// This function is given the [itemExtent] as an argument to avoid
/// recomputing [itemExtent] repeatedly during layout.
///
/// By default, returns a value consistent with the children being placed in
/// order, without gaps, starting from layout offset zero.
@protected @protected
int getMaxChildIndexForScrollOffset(double scrollOffset, double itemExtent) { int getMaxChildIndexForScrollOffset(double scrollOffset, double itemExtent) {
return itemExtent > 0.0 ? math.max(0, (scrollOffset / itemExtent).ceil() - 1) : 0; return itemExtent > 0.0 ? math.max(0, (scrollOffset / itemExtent).ceil() - 1) : 0;
} }
/// Called to estimate the total scrollable extents of this object.
///
/// Must return the total distance from the start of the child with the
/// earliest possible index to the end of the child with the last possible
/// index.
///
/// By default, defers to [RenderSliverBoxChildManager.estimateMaxScrollOffset].
@protected @protected
double estimateMaxScrollOffset(SliverConstraints constraints, { double estimateMaxScrollOffset(SliverConstraints constraints, {
int firstIndex, int firstIndex,
...@@ -78,7 +132,7 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda ...@@ -78,7 +132,7 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda
} }
if (firstChild == null) { if (firstChild == null) {
if (!addInitialChild(index: firstIndex, scrollOffset: indexToScrollOffset(itemExtent, firstIndex))) { if (!addInitialChild(index: firstIndex, layoutOffset: indexToLayoutOffset(itemExtent, firstIndex))) {
// There are no children. // There are no children.
geometry = SliverGeometry.zero; geometry = SliverGeometry.zero;
return; return;
...@@ -90,7 +144,7 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda ...@@ -90,7 +144,7 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda
for (int index = indexOf(firstChild) - 1; index >= firstIndex; --index) { for (int index = indexOf(firstChild) - 1; index >= firstIndex; --index) {
final RenderBox child = insertAndLayoutLeadingChild(childConstraints); final RenderBox child = insertAndLayoutLeadingChild(childConstraints);
final SliverMultiBoxAdaptorParentData childParentData = child.parentData; final SliverMultiBoxAdaptorParentData childParentData = child.parentData;
childParentData.layoutOffset = indexToScrollOffset(itemExtent, index); childParentData.layoutOffset = indexToLayoutOffset(itemExtent, index);
assert(childParentData.index == index); assert(childParentData.index == index);
trailingChildWithLayout ??= child; trailingChildWithLayout ??= child;
} }
...@@ -98,7 +152,7 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda ...@@ -98,7 +152,7 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda
if (trailingChildWithLayout == null) { if (trailingChildWithLayout == null) {
firstChild.layout(childConstraints); firstChild.layout(childConstraints);
final SliverMultiBoxAdaptorParentData childParentData = firstChild.parentData; final SliverMultiBoxAdaptorParentData childParentData = firstChild.parentData;
childParentData.layoutOffset = indexToScrollOffset(itemExtent, firstIndex); childParentData.layoutOffset = indexToLayoutOffset(itemExtent, firstIndex);
trailingChildWithLayout = firstChild; trailingChildWithLayout = firstChild;
} }
...@@ -116,12 +170,12 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda ...@@ -116,12 +170,12 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda
trailingChildWithLayout = child; trailingChildWithLayout = child;
assert(child != null); assert(child != null);
final SliverMultiBoxAdaptorParentData childParentData = child.parentData; final SliverMultiBoxAdaptorParentData childParentData = child.parentData;
childParentData.layoutOffset = indexToScrollOffset(itemExtent, childParentData.index); childParentData.layoutOffset = indexToLayoutOffset(itemExtent, childParentData.index);
} }
final int lastIndex = indexOf(lastChild); final int lastIndex = indexOf(lastChild);
final double leadingScrollOffset = indexToScrollOffset(itemExtent, firstIndex); final double leadingScrollOffset = indexToLayoutOffset(itemExtent, firstIndex);
final double trailingScrollOffset = indexToScrollOffset(itemExtent, lastIndex + 1); final double trailingScrollOffset = indexToLayoutOffset(itemExtent, lastIndex + 1);
assert(firstIndex == 0 || childScrollOffset(firstChild) <= scrollOffset); assert(firstIndex == 0 || childScrollOffset(firstChild) <= scrollOffset);
assert(debugAssertChildListIsNonEmptyAndContiguous()); assert(debugAssertChildListIsNonEmptyAndContiguous());
...@@ -154,7 +208,29 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda ...@@ -154,7 +208,29 @@ abstract class RenderSliverFixedExtentBoxAdaptor extends RenderSliverMultiBoxAda
} }
} }
/// A sliver that contains multiple box children that have a given extent in the
/// main axis.
///
/// [RenderSliverFixedExtentList] places its children in a linear array along
/// the main axis starting at offset zero and without gaps. Each child is forced
/// to have the [itemExtent] in the main axis and the
/// [SliverConstraints.crossAxisExtent] in the cross axis.
///
/// [RenderSliverFixedExtentList] is more efficient than [RenderSliverList]
/// because [RenderSliverFixedExtentList] does not need to perform layout on its
/// children to obtain their extent in the main axis.
///
/// See also:
///
/// * [RenderSliverFill], which determines the [itemExtent] based on
/// [SliverConstraints.viewportMainAxisExtent].
/// * [RenderSliverList], which does not require its children to have the same
/// extent in the main axis.
class RenderSliverFixedExtentList extends RenderSliverFixedExtentBoxAdaptor { class RenderSliverFixedExtentList extends RenderSliverFixedExtentBoxAdaptor {
/// Creates a sliver that contains multiple box children that have a given
/// extent in the main axis.
///
/// The [childManager] argument must not be null.
RenderSliverFixedExtentList({ RenderSliverFixedExtentList({
@required RenderSliverBoxChildManager childManager, @required RenderSliverBoxChildManager childManager,
double itemExtent, double itemExtent,
...@@ -172,7 +248,22 @@ class RenderSliverFixedExtentList extends RenderSliverFixedExtentBoxAdaptor { ...@@ -172,7 +248,22 @@ class RenderSliverFixedExtentList extends RenderSliverFixedExtentBoxAdaptor {
} }
} }
/// A sliver that contains a multiple box children that each fill the viewport.
///
/// [RenderSliverFill] places its children in a linear array along the main
/// axis. Each child is sized to fill the viewport, both in the main and cross
/// axis.
///
/// See also:
///
/// * [RenderSliverFixedExtentList], which has a configurable [itemExtent].
/// * [RenderSliverList], which does not require its children to have the same
/// extent in the main axis.
class RenderSliverFill extends RenderSliverFixedExtentBoxAdaptor { class RenderSliverFill extends RenderSliverFixedExtentBoxAdaptor {
/// Creates a sliver that contains a multiple box children that each fill the
/// viewport.
///
/// The [childManager] argument must not be null.
RenderSliverFill({ RenderSliverFill({
@required RenderSliverBoxChildManager childManager, @required RenderSliverBoxChildManager childManager,
double viewportFraction: 1.0, double viewportFraction: 1.0,
...@@ -184,6 +275,11 @@ class RenderSliverFill extends RenderSliverFixedExtentBoxAdaptor { ...@@ -184,6 +275,11 @@ class RenderSliverFill extends RenderSliverFixedExtentBoxAdaptor {
@override @override
double get itemExtent => constraints.viewportMainAxisExtent * viewportFraction; double get itemExtent => constraints.viewportMainAxisExtent * viewportFraction;
/// The fraction of the viewport that each child should fill in the main axis.
///
/// If this fraction is less than 1.0, more than one child will be visible at
/// once. If this fraction is greater than 1.0, each child will be larger than
/// the viewport in the main axis.
double get viewportFraction => _viewportFraction; double get viewportFraction => _viewportFraction;
double _viewportFraction; double _viewportFraction;
set viewportFraction(double value) { set viewportFraction(double value) {
...@@ -197,8 +293,8 @@ class RenderSliverFill extends RenderSliverFixedExtentBoxAdaptor { ...@@ -197,8 +293,8 @@ class RenderSliverFill extends RenderSliverFixedExtentBoxAdaptor {
double get _padding => (1.0 - viewportFraction) * constraints.viewportMainAxisExtent * 0.5; double get _padding => (1.0 - viewportFraction) * constraints.viewportMainAxisExtent * 0.5;
@override @override
double indexToScrollOffset(double itemExtent, int index) { double indexToLayoutOffset(double itemExtent, int index) {
return _padding + super.indexToScrollOffset(itemExtent, index); return _padding + super.indexToLayoutOffset(itemExtent, index);
} }
@override @override
......
...@@ -473,7 +473,7 @@ class RenderSliverGrid extends RenderSliverMultiBoxAdaptor { ...@@ -473,7 +473,7 @@ class RenderSliverGrid extends RenderSliverMultiBoxAdaptor {
if (firstChild == null) { if (firstChild == null) {
if (!addInitialChild(index: firstIndex, if (!addInitialChild(index: firstIndex,
scrollOffset: firstChildGridGeometry.scrollOffset)) { layoutOffset: firstChildGridGeometry.scrollOffset)) {
// There are no children. // There are no children.
geometry = SliverGeometry.zero; geometry = SliverGeometry.zero;
return; return;
......
...@@ -162,7 +162,7 @@ abstract class RenderSliverMultiBoxAdaptor extends RenderSliver ...@@ -162,7 +162,7 @@ abstract class RenderSliverMultiBoxAdaptor extends RenderSliver
/// during the call to createChild. No child should be added during that call /// during the call to createChild. No child should be added during that call
/// either, except for the one that is created and returned by createChild. /// either, except for the one that is created and returned by createChild.
@protected @protected
bool addInitialChild({ int index: 0, double scrollOffset: 0.0 }) { bool addInitialChild({ int index: 0, double layoutOffset: 0.0 }) {
assert(_debugAssertChildListLocked()); assert(_debugAssertChildListLocked());
assert(firstChild == null); assert(firstChild == null);
bool result; bool result;
...@@ -173,7 +173,7 @@ abstract class RenderSliverMultiBoxAdaptor extends RenderSliver ...@@ -173,7 +173,7 @@ abstract class RenderSliverMultiBoxAdaptor extends RenderSliver
assert(firstChild == lastChild); assert(firstChild == lastChild);
assert(indexOf(firstChild) == index); assert(indexOf(firstChild) == index);
final SliverMultiBoxAdaptorParentData firstChildParentData = firstChild.parentData; final SliverMultiBoxAdaptorParentData firstChildParentData = firstChild.parentData;
firstChildParentData.layoutOffset = scrollOffset; firstChildParentData.layoutOffset = layoutOffset;
result = true; result = true;
} else { } else {
childManager.setDidUnderflow(true); childManager.setDidUnderflow(true);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment