Commit 618e7e49 authored by Adam Barth's avatar Adam Barth

Adds a first draft of LazyBlock

LazyBlock is intended as a replacement for MixedViewport. Rather than

maintaining a table of all the observed child sizes (like

MixedViewport), LazyBlock works by dead reckoning the location of the

children based on the existing viewport. This approach makes it easier

to resize children because LazyBlock doesn't cache any additional

information that would need to be invalidated.



This patch contains a first draft of LazyBlock that works in a simple

usage scenario. Subsequent patches will replace

ScrollableMixedWidgetList with LazyBlock and port the existing

ScrollableMixedWidgetList tests over to LazyBlock.



Related to #3075
parent b9f04817
......@@ -49,6 +49,19 @@ class ComplexLayout extends StatefulWidget {
}
class FancyItemDelegate extends LazyBlockDelegate {
@override
Widget buildItem(BuildContext context, int index) {
if (index % 2 == 0)
return new FancyImageItem(index, key: new Key("Item $index"));
else
return new FancyGalleryItem(index, key: new Key("Item $index"));
}
@override
bool shouldRebuild(FancyItemDelegate oldDelegate) => false;
}
class ComplexLayoutState extends State<ComplexLayout> {
@override
Widget build(BuildContext context) {
......@@ -70,14 +83,9 @@ class ComplexLayoutState extends State<ComplexLayout> {
body: new Column(
children: <Widget>[
new Flexible(
child: new ScrollableMixedWidgetList(
child: new LazyBlock(
key: new Key("main-scroll"),
builder: (BuildContext context, int index) {
if (index % 2 == 0)
return new FancyImageItem(index, key: new Key("Item $index"));
else
return new FancyGalleryItem(index, key: new Key("Item $index"));
}
delegate: new FancyItemDelegate()
)
),
new BottomBar()
......
......@@ -80,11 +80,12 @@ abstract class RenderBlockBase extends RenderBox
bool get isVertical => _mainAxis == Axis.vertical;
BoxConstraints _getInnerConstraints(BoxConstraints constraints) {
if (isVertical)
return new BoxConstraints.tightFor(width: constraints.constrainWidth(constraints.maxWidth),
height: itemExtent);
return new BoxConstraints.tightFor(height: constraints.constrainHeight(constraints.maxHeight),
width: itemExtent);
switch (_mainAxis) {
case Axis.horizontal:
return new BoxConstraints.tightFor(height: constraints.maxHeight, width: itemExtent);
case Axis.vertical:
return new BoxConstraints.tightFor(width: constraints.maxWidth, height: itemExtent);
}
}
double get _mainAxisExtent {
......
......@@ -2452,6 +2452,11 @@ class Listener extends SingleChildRenderObjectWidget {
class RepaintBoundary extends SingleChildRenderObjectWidget {
RepaintBoundary({ Key key, Widget child }) : super(key: key, child: child);
factory RepaintBoundary.wrap(Widget child, int childIndex) {
Key key = child.key != null ? new ValueKey<Key>(child.key) : new ValueKey<int>(childIndex);
return new RepaintBoundary(key: key, child: child);
}
@override
RenderRepaintBoundary createRenderObject(BuildContext context) => new RenderRepaintBoundary();
}
......
......@@ -701,17 +701,17 @@ class BuildOwner {
/// This mechanism prevents build functions from transitively requiring other
/// build functions to run, potentially causing infinite loops.
///
/// If the building argument is true, then this is a build scope. Build scopes
/// cannot be nested.
/// If the building argument is true, then this function enables additional
/// asserts that check invariants that should apply during building.
///
/// The context argument is used to describe the scope in case an exception is
/// caught while invoking the callback.
void lockState(void callback(), { bool building: false, String context }) {
bool debugPreviouslyBuilding;
assert(_debugStateLockLevel >= 0);
assert(() {
if (building) {
assert(!_debugBuilding);
assert(_debugCurrentBuildTarget == null);
debugPreviouslyBuilding = _debugBuilding;
_debugBuilding = true;
}
_debugStateLockLevel += 1;
......@@ -726,8 +726,7 @@ class BuildOwner {
_debugStateLockLevel -= 1;
if (building) {
assert(_debugBuilding);
assert(_debugCurrentBuildTarget == null);
_debugBuilding = false;
_debugBuilding = debugPreviouslyBuilding;
}
return true;
});
......@@ -1360,6 +1359,7 @@ abstract class BuildableElement extends Element {
}
typedef Widget WidgetBuilder(BuildContext context);
typedef Widget IndexedBuilder(BuildContext context, int index);
// See _builder.
Widget _buildNothing(BuildContext context) => null;
......@@ -2088,6 +2088,7 @@ class MultiChildRenderObjectElement extends RenderObjectElement {
@override
void moveChildRenderObject(RenderObject child, dynamic slot) {
final ContainerRenderObjectMixin<RenderObject, ContainerParentDataMixin<RenderObject>> renderObject = this.renderObject;
assert(child.parent == renderObject);
renderObject.move(child, after: slot?.renderObject);
assert(renderObject == this.renderObject);
}
......
This diff is collapsed.
......@@ -9,7 +9,6 @@ import 'package:flutter/rendering.dart';
import 'framework.dart';
import 'basic.dart';
typedef Widget IndexedBuilder(BuildContext context, int index); // return null if index is greater than index of last entry
typedef void InvalidatorCallback(Iterable<int> indices);
typedef void InvalidatorAvailableCallback(InvalidatorCallback invalidator);
......
......@@ -198,7 +198,7 @@ class PageableListState<T extends PageableList> extends ScrollableState<T> {
}
@override
ScrollBehavior<double, double> createScrollBehavior() => scrollBehavior;
ExtentScrollBehavior createScrollBehavior() => scrollBehavior;
@override
bool get shouldSnapScrollOffset => config.itemsSnapAlignment == PageableListFlingBehavior.canFlingAcrossMultiplePages;
......
......@@ -659,7 +659,7 @@ class ScrollableViewport extends Scrollable {
class _ScrollableViewportState extends ScrollableState<ScrollableViewport> {
@override
ScrollBehavior<double, double> createScrollBehavior() => new OverscrollWhenScrollableBehavior();
OverscrollWhenScrollableBehavior createScrollBehavior() => new OverscrollWhenScrollableBehavior();
@override
OverscrollWhenScrollableBehavior get scrollBehavior => super.scrollBehavior;
......@@ -830,7 +830,7 @@ class ScrollableMixedWidgetListState extends ScrollableState<ScrollableMixedWidg
}
@override
ScrollBehavior<double, double> createScrollBehavior() => new OverscrollBehavior();
OverscrollBehavior createScrollBehavior() => new OverscrollBehavior();
@override
OverscrollBehavior get scrollBehavior => super.scrollBehavior;
......
......@@ -43,7 +43,7 @@ class ScrollableGrid extends Scrollable {
class _ScrollableGridState extends ScrollableState<ScrollableGrid> {
@override
ScrollBehavior<double, double> createScrollBehavior() => new OverscrollBehavior();
ExtentScrollBehavior createScrollBehavior() => new OverscrollBehavior();
@override
ExtentScrollBehavior get scrollBehavior => super.scrollBehavior;
......
......@@ -47,7 +47,7 @@ class ScrollableList extends Scrollable {
class _ScrollableListState extends ScrollableState<ScrollableList> {
@override
ScrollBehavior<double, double> createScrollBehavior() => new OverscrollWhenScrollableBehavior();
ExtentScrollBehavior createScrollBehavior() => new OverscrollWhenScrollableBehavior();
@override
ExtentScrollBehavior get scrollBehavior => super.scrollBehavior;
......@@ -330,7 +330,7 @@ class ScrollableLazyList extends Scrollable {
class _ScrollableLazyListState extends ScrollableState<ScrollableLazyList> {
@override
ScrollBehavior<double, double> createScrollBehavior() => new OverscrollBehavior();
ExtentScrollBehavior createScrollBehavior() => new OverscrollBehavior();
@override
ExtentScrollBehavior get scrollBehavior => super.scrollBehavior;
......
......@@ -170,8 +170,7 @@ abstract class VirtualViewportElement extends RenderObjectElement {
for (int i = 0; i < count; ++i) {
int childIndex = base + i;
Widget child = _widgetProvider.getChild(childIndex);
Key key = child.key != null ? new ValueKey<Key>(child.key) : new ValueKey<int>(childIndex);
newWidgets[i] = new RepaintBoundary(key: key, child: child);
newWidgets[i] = new RepaintBoundary.wrap(child, childIndex);
}
assert(!debugChildrenHaveDuplicateKeys(widget, newWidgets));
......
......@@ -23,6 +23,7 @@ export 'src/widgets/gesture_detector.dart';
export 'src/widgets/gridpaper.dart';
export 'src/widgets/heroes.dart';
export 'src/widgets/implicit_animations.dart';
export 'src/widgets/lazy_block.dart';
export 'src/widgets/locale_query.dart';
export 'src/widgets/media_query.dart';
export 'src/widgets/mimic.dart';
......
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