Commit e2a6b488 authored by Adam Barth's avatar Adam Barth

Merge pull request #2418 from abarth/viewport_docs

Add dartdoc to VirtualViewport widgets
parents 03db132f 24c0ab7f
...@@ -9,20 +9,33 @@ import 'package:vector_math/vector_math_64.dart'; ...@@ -9,20 +9,33 @@ import 'package:vector_math/vector_math_64.dart';
import 'box.dart'; import 'box.dart';
import 'object.dart'; import 'object.dart';
/// The end of the viewport from which the paint offset is computed.
enum ViewportAnchor { enum ViewportAnchor {
/// The start (e.g., top or left, depending on the axis) of the first item
/// should be aligned with the start (e.g., top or left, depending on the
/// axis) of the viewport.
start, start,
/// The end (e.g., bottom or right, depending on the axis) of the last item
/// should be aligned with the end (e.g., bottom or right, depending on the
/// axis) of the viewport.
end, end,
} }
/// The interior and exterior dimensions of a viewport.
class ViewportDimensions { class ViewportDimensions {
const ViewportDimensions({ const ViewportDimensions({
this.contentSize: Size.zero, this.contentSize: Size.zero,
this.containerSize: Size.zero this.containerSize: Size.zero
}); });
/// A viewport that has zero size, both inside and outside.
static const ViewportDimensions zero = const ViewportDimensions(); static const ViewportDimensions zero = const ViewportDimensions();
/// The size of the content inside the viewport.
final Size contentSize; final Size contentSize;
/// The size of the outside of the viewport.
final Size containerSize; final Size containerSize;
bool get _debugHasAtLeastOneCommonDimension { bool get _debugHasAtLeastOneCommonDimension {
...@@ -30,6 +43,8 @@ class ViewportDimensions { ...@@ -30,6 +43,8 @@ class ViewportDimensions {
|| contentSize.height == containerSize.height; || contentSize.height == containerSize.height;
} }
/// Returns the offset at which to paint the content, accounting for the given
/// anchor and the dimensions of the viewport.
Offset getAbsolutePaintOffset({ Offset paintOffset, ViewportAnchor anchor }) { Offset getAbsolutePaintOffset({ Offset paintOffset, ViewportAnchor anchor }) {
assert(_debugHasAtLeastOneCommonDimension); assert(_debugHasAtLeastOneCommonDimension);
switch (anchor) { switch (anchor) {
...@@ -55,7 +70,9 @@ class ViewportDimensions { ...@@ -55,7 +70,9 @@ class ViewportDimensions {
String toString() => 'ViewportDimensions(container: $containerSize, content: $contentSize)'; String toString() => 'ViewportDimensions(container: $containerSize, content: $contentSize)';
} }
/// An interface that indicates that an object has a scroll direction.
abstract class HasScrollDirection { abstract class HasScrollDirection {
/// Whether this object scrolls horizontally or vertically.
Axis get scrollDirection; Axis get scrollDirection;
} }
...@@ -119,6 +136,9 @@ class RenderViewportBase extends RenderBox implements HasScrollDirection { ...@@ -119,6 +136,9 @@ class RenderViewportBase extends RenderBox implements HasScrollDirection {
markNeedsLayout(); markNeedsLayout();
} }
/// The end of the viewport from which the paint offset is computed.
///
/// See [ViewportAnchor] for more detail.
ViewportAnchor get scrollAnchor => _scrollAnchor; ViewportAnchor get scrollAnchor => _scrollAnchor;
ViewportAnchor _scrollAnchor; ViewportAnchor _scrollAnchor;
void set scrollAnchor(ViewportAnchor value) { void set scrollAnchor(ViewportAnchor value) {
......
...@@ -202,7 +202,7 @@ class PageableListState<T extends PageableList> extends ScrollableState<T> { ...@@ -202,7 +202,7 @@ class PageableListState<T extends PageableList> extends ScrollableState<T> {
} }
} }
class PageViewport extends VirtualViewport with VirtualViewportIterableMixin { class PageViewport extends VirtualViewportFromIterable {
PageViewport({ PageViewport({
this.startOffset: 0.0, this.startOffset: 0.0,
this.scrollDirection: Axis.vertical, this.scrollDirection: Axis.vertical,
......
...@@ -63,7 +63,7 @@ class _ScrollableGridState extends ScrollableState<ScrollableGrid> { ...@@ -63,7 +63,7 @@ class _ScrollableGridState extends ScrollableState<ScrollableGrid> {
} }
} }
class GridViewport extends VirtualViewport with VirtualViewportIterableMixin { class GridViewport extends VirtualViewportFromIterable {
GridViewport({ GridViewport({
this.startOffset, this.startOffset,
this.delegate, this.delegate,
......
...@@ -240,7 +240,7 @@ class _VirtualListViewportElement extends VirtualViewportElement<_VirtualListVie ...@@ -240,7 +240,7 @@ class _VirtualListViewportElement extends VirtualViewportElement<_VirtualListVie
} }
} }
class ListViewport extends _VirtualListViewport with VirtualViewportIterableMixin { class ListViewport extends _VirtualListViewport with VirtualViewportFromIterable {
ListViewport({ ListViewport({
ExtentsChangedCallback onExtentsChanged, ExtentsChangedCallback onExtentsChanged,
double scrollOffset: 0.0, double scrollOffset: 0.0,
...@@ -350,7 +350,7 @@ class _ScrollableLazyListState extends ScrollableState<ScrollableLazyList> { ...@@ -350,7 +350,7 @@ class _ScrollableLazyListState extends ScrollableState<ScrollableLazyList> {
} }
} }
class LazyListViewport extends _VirtualListViewport with VirtualViewportLazyMixin { class LazyListViewport extends _VirtualListViewport with VirtualViewportFromBuilder {
LazyListViewport({ LazyListViewport({
ExtentsChangedCallback onExtentsChanged, ExtentsChangedCallback onExtentsChanged,
double scrollOffset: 0.0, double scrollOffset: 0.0,
......
...@@ -11,7 +11,9 @@ import 'package:flutter/rendering.dart'; ...@@ -11,7 +11,9 @@ import 'package:flutter/rendering.dart';
typedef void ExtentsChangedCallback(double contentExtent, double containerExtent); typedef void ExtentsChangedCallback(double contentExtent, double containerExtent);
/// An abstract widget whose children are not all materialized.
abstract class VirtualViewport extends RenderObjectWidget { abstract class VirtualViewport extends RenderObjectWidget {
/// The offset from the [ViewportAnchor] at which the viewport should start painting children.
double get startOffset; double get startOffset;
_WidgetProvider _createWidgetProvider(); _WidgetProvider _createWidgetProvider();
...@@ -24,12 +26,24 @@ abstract class _WidgetProvider { ...@@ -24,12 +26,24 @@ abstract class _WidgetProvider {
Widget getChild(int i); Widget getChild(int i);
} }
/// Materializes a contiguous subset of its children.
///
/// This class is a building block for building a widget that has more children
/// than it wishes to display at any given time. For example, [ScrollableList]
/// uses this element to materialize only those children that are visible.
abstract class VirtualViewportElement<T extends VirtualViewport> extends RenderObjectElement<T> { abstract class VirtualViewportElement<T extends VirtualViewport> extends RenderObjectElement<T> {
VirtualViewportElement(T widget) : super(widget); VirtualViewportElement(T widget) : super(widget);
/// The index of the first child to materialize.
int get materializedChildBase; int get materializedChildBase;
/// The number of children to materializes.
int get materializedChildCount; int get materializedChildCount;
/// The least offset for which [materializedChildBase] and [materializedChildCount] are valid.
double get startOffsetBase; double get startOffsetBase;
/// The greatest offset for which [materializedChildBase] and [materializedChildCount] are valid.
double get startOffsetLimit; double get startOffsetLimit;
/// Returns the pixel offset for a scroll offset, accounting for the scroll /// Returns the pixel offset for a scroll offset, accounting for the scroll
...@@ -124,6 +138,12 @@ abstract class VirtualViewportElement<T extends VirtualViewport> extends RenderO ...@@ -124,6 +138,12 @@ abstract class VirtualViewportElement<T extends VirtualViewport> extends RenderO
} }
} }
/// Called by [RenderVirtualViewport] during layout.
///
/// Subclasses should override this function to compute [materializedChildBase]
/// and [materializedChildCount]. Overrides should call this function to
/// update the [RenderVirtualViewport]'s paint offset and to materialize the
/// children.
void layout(BoxConstraints constraints) { void layout(BoxConstraints constraints) {
assert(startOffsetBase != null); assert(startOffsetBase != null);
assert(startOffsetLimit != null); assert(startOffsetLimit != null);
...@@ -162,7 +182,12 @@ abstract class VirtualViewportElement<T extends VirtualViewport> extends RenderO ...@@ -162,7 +182,12 @@ abstract class VirtualViewportElement<T extends VirtualViewport> extends RenderO
} }
} }
abstract class VirtualViewportIterableMixin extends VirtualViewport { /// A VirtualViewport that represents its children using [Iterable<Widget>].
///
/// The iterator is advanced just far enough to obtain widgets for the children
/// that need to be materialized.
abstract class VirtualViewportFromIterable extends VirtualViewport {
/// The children, some of which might be materialized.
Iterable<Widget> get children; Iterable<Widget> get children;
_IterableWidgetProvider _createWidgetProvider() => new _IterableWidgetProvider(); _IterableWidgetProvider _createWidgetProvider() => new _IterableWidgetProvider();
...@@ -173,7 +198,7 @@ class _IterableWidgetProvider extends _WidgetProvider { ...@@ -173,7 +198,7 @@ class _IterableWidgetProvider extends _WidgetProvider {
Iterator<Widget> _iterator; Iterator<Widget> _iterator;
List<Widget> _widgets; List<Widget> _widgets;
void didUpdateWidget(VirtualViewportIterableMixin oldWidget, VirtualViewportIterableMixin newWidget) { void didUpdateWidget(VirtualViewportFromIterable oldWidget, VirtualViewportFromIterable newWidget) {
if (oldWidget == null || newWidget.children != oldWidget.children) { if (oldWidget == null || newWidget.children != oldWidget.children) {
_iterator = null; _iterator = null;
_widgets = <Widget>[]; _widgets = <Widget>[];
...@@ -187,7 +212,7 @@ class _IterableWidgetProvider extends _WidgetProvider { ...@@ -187,7 +212,7 @@ class _IterableWidgetProvider extends _WidgetProvider {
int limit = base < 0 ? _length : math.min(_length, base + count); int limit = base < 0 ? _length : math.min(_length, base + count);
if (limit <= _widgets.length) if (limit <= _widgets.length)
return; return;
VirtualViewportIterableMixin widget = context.widget; VirtualViewportFromIterable widget = context.widget;
if (widget.children is List<Widget>) { if (widget.children is List<Widget>) {
_widgets = widget.children; _widgets = widget.children;
return; return;
...@@ -205,10 +230,21 @@ class _IterableWidgetProvider extends _WidgetProvider { ...@@ -205,10 +230,21 @@ class _IterableWidgetProvider extends _WidgetProvider {
Widget getChild(int i) => _widgets[(i % _length).abs()]; Widget getChild(int i) => _widgets[(i % _length).abs()];
} }
/// Signature of a callback that returns the sublist of widgets in the given range.
typedef List<Widget> ItemListBuilder(BuildContext context, int start, int count); typedef List<Widget> ItemListBuilder(BuildContext context, int start, int count);
abstract class VirtualViewportLazyMixin extends VirtualViewport { /// A VirtualViewport that represents its children using [ItemListBuilder].
///
/// This widget is less ergonomic than [VirtualViewportFromIterable] but scales to
/// unlimited numbers of children.
abstract class VirtualViewportFromBuilder extends VirtualViewport {
/// The total number of children that can be built.
int get itemCount; int get itemCount;
/// A callback to build the subset of widgets that are needed to populate the
/// viewport. Not all of the returned widgets will actually be included in the
/// viewport (e.g., if we need to measure the size of non-visible children to
/// determine which children are visible).
ItemListBuilder get itemBuilder; ItemListBuilder get itemBuilder;
_LazyWidgetProvider _createWidgetProvider() => new _LazyWidgetProvider(); _LazyWidgetProvider _createWidgetProvider() => new _LazyWidgetProvider();
...@@ -219,7 +255,7 @@ class _LazyWidgetProvider extends _WidgetProvider { ...@@ -219,7 +255,7 @@ class _LazyWidgetProvider extends _WidgetProvider {
int _base; int _base;
List<Widget> _widgets; List<Widget> _widgets;
void didUpdateWidget(VirtualViewportLazyMixin oldWidget, VirtualViewportLazyMixin newWidget) { void didUpdateWidget(VirtualViewportFromBuilder oldWidget, VirtualViewportFromBuilder newWidget) {
if (_length != newWidget.itemCount || oldWidget?.itemBuilder != newWidget.itemBuilder) { if (_length != newWidget.itemCount || oldWidget?.itemBuilder != newWidget.itemBuilder) {
_length = newWidget.itemCount; _length = newWidget.itemCount;
_base = null; _base = null;
...@@ -232,7 +268,7 @@ class _LazyWidgetProvider extends _WidgetProvider { ...@@ -232,7 +268,7 @@ class _LazyWidgetProvider extends _WidgetProvider {
void prepareChildren(VirtualViewportElement context, int base, int count) { void prepareChildren(VirtualViewportElement context, int base, int count) {
if (_widgets != null && _widgets.length == count && _base == base) if (_widgets != null && _widgets.length == count && _base == base)
return; return;
VirtualViewportLazyMixin widget = context.widget; VirtualViewportFromBuilder widget = context.widget;
_base = base; _base = base;
_widgets = widget.itemBuilder(context, base, count); _widgets = widget.itemBuilder(context, base, count);
} }
......
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