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