Commit 40899eb2 authored by Adam Barth's avatar Adam Barth

Port clients of ScrollableMixedWidgetList to LazyBlock

LazyBlock is going to replace ScrollableMixedWidgetList at some point.
parent bd407cea
...@@ -44,7 +44,6 @@ class CardCollectionState extends State<CardCollection> { ...@@ -44,7 +44,6 @@ class CardCollectionState extends State<CardCollection> {
bool _fixedSizeCards = false; bool _fixedSizeCards = false;
bool _sunshine = false; bool _sunshine = false;
bool _varyFontSizes = false; bool _varyFontSizes = false;
InvalidatorCallback _invalidator;
void _initVariableSizedCardModels() { void _initVariableSizedCardModels() {
List<double> cardHeights = <double>[ List<double> cardHeights = <double>[
...@@ -304,7 +303,6 @@ class CardCollectionState extends State<CardCollection> { ...@@ -304,7 +303,6 @@ class CardCollectionState extends State<CardCollection> {
Widget card = new Dismissable( Widget card = new Dismissable(
key: new ObjectKey(cardModel), key: new ObjectKey(cardModel),
direction: _dismissDirection, direction: _dismissDirection,
onResize: () { if (_invalidator != null) _invalidator(<int>[index]); },
onDismissed: (DismissDirection direction) { dismissCard(cardModel); }, onDismissed: (DismissDirection direction) { dismissCard(cardModel); },
child: new Card( child: new Card(
color: _primaryColor[cardModel.color], color: _primaryColor[cardModel.color],
...@@ -413,18 +411,15 @@ class CardCollectionState extends State<CardCollection> { ...@@ -413,18 +411,15 @@ class CardCollectionState extends State<CardCollection> {
Widget build(BuildContext context) { Widget build(BuildContext context) {
Widget cardCollection; Widget cardCollection;
if (_fixedSizeCards) { if (_fixedSizeCards) {
_invalidator = null;
cardCollection = new ScrollableList( cardCollection = new ScrollableList(
snapOffsetCallback: _snapToCenter ? _toSnapOffset : null, snapOffsetCallback: _snapToCenter ? _toSnapOffset : null,
itemExtent: kFixedCardHeight, itemExtent: kFixedCardHeight,
children: _cardIndices.map/*<Widget>*/((int index) => _buildCard(context, index)) children: _cardIndices.map/*<Widget>*/((int index) => _buildCard(context, index))
); );
} else { } else {
cardCollection = new ScrollableMixedWidgetList( cardCollection = new LazyBlock(
builder: _buildCard, delegate: new LazyBlockBuilder(_buildCard),
token: _cardModels.length, snapOffsetCallback: _snapToCenter ? _toSnapOffset : null
snapOffsetCallback: _snapToCenter ? _toSnapOffset : null,
onInvalidatorAvailable: (InvalidatorCallback callback) { _invalidator = callback; }
); );
} }
......
...@@ -90,11 +90,44 @@ class OverlayGeometryApp extends StatefulWidget { ...@@ -90,11 +90,44 @@ class OverlayGeometryApp extends StatefulWidget {
OverlayGeometryAppState createState() => new OverlayGeometryAppState(); OverlayGeometryAppState createState() => new OverlayGeometryAppState();
} }
class OverlayGeometryAppState extends State<OverlayGeometryApp> { typedef void CardTapCallback(Key targetKey, Point globalPosition);
class CardBuilder extends LazyBlockDelegate {
CardBuilder({ this.cardModels, this.onTapUp });
final List<CardModel> cardModels;
final CardTapCallback onTapUp;
static const TextStyle cardLabelStyle = static const TextStyle cardLabelStyle =
const TextStyle(color: Colors.white, fontSize: 18.0, fontWeight: FontWeight.bold); const TextStyle(color: Colors.white, fontSize: 18.0, fontWeight: FontWeight.bold);
@override
Widget buildItem(BuildContext context, int index) {
if (index >= cardModels.length)
return null;
CardModel cardModel = cardModels[index];
return new GestureDetector(
key: cardModel.key,
onTapUp: (Point globalPosition) { onTapUp(cardModel.targetKey, globalPosition); },
child: new Card(
key: cardModel.targetKey,
color: cardModel.color,
child: new Container(
height: cardModel.height,
padding: const EdgeInsets.all(8.0),
child: new Center(child: new Text(cardModel.label, style: cardLabelStyle))
)
)
);
}
@override
bool shouldRebuild(CardBuilder oldDelegate) {
return oldDelegate.cardModels != cardModels;
}
}
class OverlayGeometryAppState extends State<OverlayGeometryApp> {
List<CardModel> cardModels; List<CardModel> cardModels;
Map<MarkerType, Point> markers = new Map<MarkerType, Point>(); Map<MarkerType, Point> markers = new Map<MarkerType, Point>();
double markersScrollOffset; double markersScrollOffset;
...@@ -125,9 +158,9 @@ class OverlayGeometryAppState extends State<OverlayGeometryApp> { ...@@ -125,9 +158,9 @@ class OverlayGeometryAppState extends State<OverlayGeometryApp> {
}); });
} }
void handlePointerDown(GlobalKey target, PointerDownEvent event) { void handleTapUp(GlobalKey target, Point globalPosition) {
setState(() { setState(() {
markers[MarkerType.touch] = event.position; markers[MarkerType.touch] = globalPosition;
final RenderBox box = target.currentContext.findRenderObject(); final RenderBox box = target.currentContext.findRenderObject();
markers[MarkerType.topLeft] = box.localToGlobal(new Point(0.0, 0.0)); markers[MarkerType.topLeft] = box.localToGlobal(new Point(0.0, 0.0));
final Size size = box.size; final Size size = box.size;
...@@ -137,25 +170,6 @@ class OverlayGeometryAppState extends State<OverlayGeometryApp> { ...@@ -137,25 +170,6 @@ class OverlayGeometryAppState extends State<OverlayGeometryApp> {
}); });
} }
Widget builder(BuildContext context, int index) {
if (index >= cardModels.length)
return null;
CardModel cardModel = cardModels[index];
return new Listener(
key: cardModel.key,
onPointerDown: (PointerDownEvent event) { return handlePointerDown(cardModel.targetKey, event); },
child: new Card(
key: cardModel.targetKey,
color: cardModel.color,
child: new Container(
height: cardModel.height,
padding: const EdgeInsets.all(8.0),
child: new Center(child: new Text(cardModel.label, style: cardLabelStyle))
)
)
);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
List<Widget> layers = <Widget>[ List<Widget> layers = <Widget>[
...@@ -163,10 +177,12 @@ class OverlayGeometryAppState extends State<OverlayGeometryApp> { ...@@ -163,10 +177,12 @@ class OverlayGeometryAppState extends State<OverlayGeometryApp> {
appBar: new AppBar(title: new Text('Tap a Card')), appBar: new AppBar(title: new Text('Tap a Card')),
body: new Container( body: new Container(
padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 8.0), padding: const EdgeInsets.symmetric(vertical: 12.0, horizontal: 8.0),
child: new ScrollableMixedWidgetList( child: new LazyBlock(
builder: builder, onScroll: handleScroll,
token: cardModels.length, delegate: new CardBuilder(
onScroll: handleScroll cardModels: cardModels,
onTapUp: handleTapUp
)
) )
) )
) )
......
...@@ -33,6 +33,18 @@ abstract class LazyBlockDelegate { ...@@ -33,6 +33,18 @@ abstract class LazyBlockDelegate {
bool shouldRebuild(LazyBlockDelegate oldDelegate); bool shouldRebuild(LazyBlockDelegate oldDelegate);
} }
class LazyBlockBuilder extends LazyBlockDelegate {
LazyBlockBuilder(this.builder);
final IndexedBuilder builder;
@override
Widget buildItem(BuildContext context, int index) => builder(context, index);
@override
bool shouldRebuild(LazyBlockDelegate oldDelegate) => true;
}
class LazyBlock extends Scrollable { class LazyBlock extends Scrollable {
LazyBlock({ LazyBlock({
Key key, Key key,
...@@ -124,18 +136,19 @@ class _RenderLazyBlock extends RenderVirtualViewport<_LazyBlockParentData> { ...@@ -124,18 +136,19 @@ class _RenderLazyBlock extends RenderVirtualViewport<_LazyBlockParentData> {
child.parentData = new _LazyBlockParentData(); child.parentData = new _LazyBlockParentData();
} }
double _noIntrinsicExtent() { bool _debugThrowIfNotCheckingIntrinsics() {
assert(() { assert(() {
if (!RenderObject.debugCheckingIntrinsics) { if (!RenderObject.debugCheckingIntrinsics) {
throw new UnsupportedError( throw new FlutterError(
'MixedViewport does not support returning intrinsic dimensions.\n' 'LazyBlockViewport does not support returning intrinsic dimensions.\n'
'Calculating the intrinsic dimensions would require walking the entire child list,\n' 'Calculating the intrinsic dimensions would require walking the entire '
'which defeats the entire point of having a lazily-built list of children.' 'child list, which defeats the entire point of having a lazily-built '
'list of children.'
); );
} }
return true; return true;
}); });
return null; return true;
} }
double getIntrinsicWidth(BoxConstraints constraints) { double getIntrinsicWidth(BoxConstraints constraints) {
...@@ -143,7 +156,8 @@ class _RenderLazyBlock extends RenderVirtualViewport<_LazyBlockParentData> { ...@@ -143,7 +156,8 @@ class _RenderLazyBlock extends RenderVirtualViewport<_LazyBlockParentData> {
case Axis.horizontal: case Axis.horizontal:
return constraints.constrainWidth(0.0); return constraints.constrainWidth(0.0);
case Axis.vertical: case Axis.vertical:
return _noIntrinsicExtent(); assert(_debugThrowIfNotCheckingIntrinsics());
return constraints.constrainWidth(0.0);
} }
} }
...@@ -162,9 +176,10 @@ class _RenderLazyBlock extends RenderVirtualViewport<_LazyBlockParentData> { ...@@ -162,9 +176,10 @@ class _RenderLazyBlock extends RenderVirtualViewport<_LazyBlockParentData> {
double getIntrinsicHeight(BoxConstraints constraints) { double getIntrinsicHeight(BoxConstraints constraints) {
switch (mainAxis) { switch (mainAxis) {
case Axis.horizontal: case Axis.horizontal:
return constraints.constrainWidth(0.0); return constraints.constrainHeight(0.0);
case Axis.vertical: case Axis.vertical:
return _noIntrinsicExtent(); assert(_debugThrowIfNotCheckingIntrinsics());
return constraints.constrainHeight(0.0);
} }
} }
...@@ -259,13 +274,19 @@ class _LazyBlockElement extends RenderObjectElement { ...@@ -259,13 +274,19 @@ class _LazyBlockElement extends RenderObjectElement {
LazyBlockViewport oldWidget = widget; LazyBlockViewport oldWidget = widget;
super.update(newWidget); super.update(newWidget);
renderObject.mainAxis = widget.direction; renderObject.mainAxis = widget.direction;
if (newWidget.delegate.runtimeType != oldWidget.delegate.runtimeType || LazyBlockDelegate newDelegate = newWidget.delegate;
newWidget.delegate.shouldRebuild(oldWidget.delegate)) { LazyBlockDelegate oldDelegate = oldWidget.delegate;
IndexedBuilder builder = widget.delegate.buildItem; if (newDelegate != oldDelegate && (newDelegate.runtimeType != oldDelegate.runtimeType || newDelegate.shouldRebuild(oldDelegate))) {
List<Widget> widgets = new List<Widget>(_children.length); IndexedBuilder builder = newDelegate.buildItem;
for (int i = 0; i < widgets.length; ++i) List<Widget> widgets = <Widget>[];
widgets[i] = builder(this, _firstChildLogicalIndex + i); for (int i = 0; i < widgets.length; ++i) {
_children = updateChildren(_children, widgets); int logicalIndex = _firstChildLogicalIndex + i;
Widget childWidget = builder(this, logicalIndex);
if (childWidget == null)
break;
widgets[i] = new RepaintBoundary.wrap(childWidget, logicalIndex);
}
_children = new List<Element>.from(updateChildren(_children, widgets));
} }
// If the new start offset can be displayed properly with the items // If the new start offset can be displayed properly with the items
// currently represented in _children, we just need to update the paint // currently represented in _children, we just need to update the paint
...@@ -316,8 +337,9 @@ class _LazyBlockElement extends RenderObjectElement { ...@@ -316,8 +337,9 @@ class _LazyBlockElement extends RenderObjectElement {
while (currentLogicalIndex > 0 && currentLogicalOffset > startLogicalOffset) { while (currentLogicalIndex > 0 && currentLogicalOffset > startLogicalOffset) {
currentLogicalIndex -= 1; currentLogicalIndex -= 1;
Widget newWidget = new RepaintBoundary.wrap(builder(this, currentLogicalIndex), currentLogicalIndex); Widget newWidget = builder(this, currentLogicalIndex);
assert(newWidget != null); assert(newWidget != null);
newWidget = new RepaintBoundary.wrap(newWidget, currentLogicalIndex);
newChildren.add(inflateWidget(newWidget, null)); newChildren.add(inflateWidget(newWidget, null));
RenderBox child = block.firstChild; RenderBox child = block.firstChild;
assert(child == newChildren.last.renderObject); assert(child == newChildren.last.renderObject);
...@@ -383,9 +405,10 @@ class _LazyBlockElement extends RenderObjectElement { ...@@ -383,9 +405,10 @@ class _LazyBlockElement extends RenderObjectElement {
int physicalIndex = currentLogicalIndex - _firstChildLogicalIndex; int physicalIndex = currentLogicalIndex - _firstChildLogicalIndex;
if (physicalIndex >= _children.length) { if (physicalIndex >= _children.length) {
assert(physicalIndex == _children.length); assert(physicalIndex == _children.length);
Widget newWidget = new RepaintBoundary.wrap(builder(this, currentLogicalIndex), currentLogicalIndex); Widget newWidget = builder(this, currentLogicalIndex);
if (newWidget == null) if (newWidget == null)
break; break;
newWidget = new RepaintBoundary.wrap(newWidget, currentLogicalIndex);
Element previousChild = _children.isEmpty ? null : _children.last; Element previousChild = _children.isEmpty ? null : _children.last;
_children.add(inflateWidget(newWidget, previousChild)); _children.add(inflateWidget(newWidget, previousChild));
} }
......
...@@ -21,13 +21,9 @@ Widget buildCard(BuildContext context, int index) { ...@@ -21,13 +21,9 @@ Widget buildCard(BuildContext context, int index) {
); );
} }
InvalidatorCallback invalidator;
Widget buildFrame() { Widget buildFrame() {
return new ScrollableMixedWidgetList( return new LazyBlock(
builder: buildCard, delegate: new LazyBlockBuilder(buildCard)
token: items.length,
onInvalidatorAvailable: (InvalidatorCallback callback) { invalidator = callback; }
); );
} }
......
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