mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
Port clients of ScrollableMixedWidgetList to LazyBlock
LazyBlock is going to replace ScrollableMixedWidgetList at some point.
This commit is contained in:
parent
bd407cea0d
commit
40899eb274
@ -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> {
|
|||||||
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> {
|
|||||||
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 {
|
|||||||
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> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
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> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
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> {
|
|||||||
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 {
|
|||||||
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> {
|
|||||||
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> {
|
|||||||
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> {
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
|
|
||||||
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 {
|
|||||||
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) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
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; }
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user