Commit 2d49e807 authored by Adam Barth's avatar Adam Barth

Remove MixedViewport

Also, port the MixedViewport tests to LazyBlockViewport. Fix bugs found by the tests.
parent 2383d605
...@@ -1241,6 +1241,11 @@ class ErrorWidget extends LeafRenderObjectWidget { ...@@ -1241,6 +1241,11 @@ class ErrorWidget extends LeafRenderObjectWidget {
@override @override
RenderBox createRenderObject(BuildContext context) => new RenderErrorBox(message); RenderBox createRenderObject(BuildContext context) => new RenderErrorBox(message);
@override
void debugFillDescription(List<String> description) {
description.add('message: ' + _stringify(message));
}
} }
/// Base class for instantiations of widgets that have builders and can be /// Base class for instantiations of widgets that have builders and can be
......
...@@ -377,18 +377,8 @@ class _LazyBlockElement extends RenderObjectElement { ...@@ -377,18 +377,8 @@ class _LazyBlockElement extends RenderObjectElement {
renderObject.mainAxis = widget.mainAxis; renderObject.mainAxis = widget.mainAxis;
LazyBlockDelegate newDelegate = newWidget.delegate; LazyBlockDelegate newDelegate = newWidget.delegate;
LazyBlockDelegate oldDelegate = oldWidget.delegate; LazyBlockDelegate oldDelegate = oldWidget.delegate;
if (newDelegate != oldDelegate && (newDelegate.runtimeType != oldDelegate.runtimeType || newDelegate.shouldRebuild(oldDelegate))) { if (newDelegate != oldDelegate && (newDelegate.runtimeType != oldDelegate.runtimeType || newDelegate.shouldRebuild(oldDelegate)))
IndexedBuilder builder = newDelegate.buildItem; performRebuild();
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 // 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
// offset. Otherwise, we need to trigger a layout in order to change the // offset. Otherwise, we need to trigger a layout in order to change the
...@@ -405,6 +395,21 @@ class _LazyBlockElement extends RenderObjectElement { ...@@ -405,6 +395,21 @@ class _LazyBlockElement extends RenderObjectElement {
super.unmount(); super.unmount();
} }
@override
void performRebuild() {
IndexedBuilder builder = widget.delegate.buildItem;
List<Widget> widgets = <Widget>[];
for (int i = 0; i < _children.length; ++i) {
int logicalIndex = _firstChildLogicalIndex + i;
Widget childWidget = builder(this, logicalIndex);
if (childWidget == null)
break;
widgets.add(new RepaintBoundary.wrap(childWidget, logicalIndex));
}
_children = new List<Element>.from(updateChildren(_children, widgets));
super.performRebuild();
}
void _layout(BoxConstraints constraints) { void _layout(BoxConstraints constraints) {
final double blockExtent = _getMainAxisExtent(renderObject.size); final double blockExtent = _getMainAxisExtent(renderObject.size);
......
This diff is collapsed.
...@@ -13,7 +13,6 @@ import 'package:flutter/rendering.dart' show HasMainAxis; ...@@ -13,7 +13,6 @@ import 'package:flutter/rendering.dart' show HasMainAxis;
import 'basic.dart'; import 'basic.dart';
import 'framework.dart'; import 'framework.dart';
import 'gesture_detector.dart'; import 'gesture_detector.dart';
import 'mixed_viewport.dart';
import 'notification_listener.dart'; import 'notification_listener.dart';
import 'page_storage.dart'; import 'page_storage.dart';
import 'scroll_behavior.dart'; import 'scroll_behavior.dart';
...@@ -612,11 +611,10 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> { ...@@ -612,11 +611,10 @@ abstract class ScrollableState<T extends Scrollable> extends State<T> {
/// The widgets used by this method should be widgets that provide a /// The widgets used by this method should be widgets that provide a
/// layout-time callback that reports the sizes that are relevant to /// layout-time callback that reports the sizes that are relevant to
/// the scroll offset (typically the size of the scrollable /// the scroll offset (typically the size of the scrollable
/// container and the scrolled contents). [Viewport] and /// container and the scrolled contents). [Viewport] provides an
/// [MixedViewport] provide an [onPaintOffsetUpdateNeeded] callback /// [onPaintOffsetUpdateNeeded] callback for this purpose; [GridViewport],
/// for this purpose; [GridViewport], [ListViewport], and /// [ListViewport], [LazyListViewport], and [LazyBlockViewport] provide an
/// [LazyListViewport] provide an [onExtentsChanged] callback for /// [onExtentsChanged] callback for this purpose.
/// this purpose.
/// ///
/// This callback should be used to update the scroll behavior, if /// This callback should be used to update the scroll behavior, if
/// necessary, and then to call [updateGestureDetector] to update /// necessary, and then to call [updateGestureDetector] to update
...@@ -705,6 +703,10 @@ class _ScrollableViewportState extends ScrollableState<ScrollableViewport> { ...@@ -705,6 +703,10 @@ class _ScrollableViewportState extends ScrollableState<ScrollableViewport> {
/// A mashup of [ScrollableViewport] and [BlockBody]. Useful when you have a small, /// A mashup of [ScrollableViewport] and [BlockBody]. Useful when you have a small,
/// fixed number of children that you wish to arrange in a block layout and that /// fixed number of children that you wish to arrange in a block layout and that
/// might exceed the height of its container (and therefore need to scroll). /// might exceed the height of its container (and therefore need to scroll).
///
/// If you have a large number of children, consider using [LazyBlock] (if the
/// children have variable height) or [ScrollableList] (if the children all have
/// the same fixed height).
class Block extends StatelessWidget { class Block extends StatelessWidget {
Block({ Block({
Key key, Key key,
...@@ -794,76 +796,3 @@ abstract class ScrollableListPainter extends RenderObjectPainter { ...@@ -794,76 +796,3 @@ abstract class ScrollableListPainter extends RenderObjectPainter {
/// or was canceled by the user. /// or was canceled by the user.
Future<Null> scrollEnded() => new Future<Null>.value(); Future<Null> scrollEnded() => new Future<Null>.value();
} }
/// A general scrollable list for a large number of children that might not all
/// have the same height. Prefer [ScrollableList] when all the children
/// have the same height because it can use that property to be more efficient.
/// Prefer [ScrollableViewport] with a single child.
///
/// ScrollableMixedWidgetList only supports vertical scrolling.
class ScrollableMixedWidgetList extends Scrollable {
ScrollableMixedWidgetList({
Key key,
double initialScrollOffset,
ScrollListener onScroll,
SnapOffsetCallback snapOffsetCallback,
this.builder,
this.token,
this.onInvalidatorAvailable
}) : super(
key: key,
initialScrollOffset: initialScrollOffset,
onScroll: onScroll,
snapOffsetCallback: snapOffsetCallback
);
// TODO(ianh): Support horizontal scrolling.
final IndexedBuilder builder;
final Object token;
final InvalidatorAvailableCallback onInvalidatorAvailable;
@override
ScrollableMixedWidgetListState createState() => new ScrollableMixedWidgetListState();
}
class ScrollableMixedWidgetListState extends ScrollableState<ScrollableMixedWidgetList> {
@override
void initState() {
super.initState();
scrollBehavior.updateExtents(
contentExtent: double.INFINITY
);
}
@override
OverscrollBehavior createScrollBehavior() => new OverscrollBehavior();
@override
OverscrollBehavior get scrollBehavior => super.scrollBehavior;
Offset _handlePaintOffsetUpdateNeeded(ViewportDimensions dimensions) {
// We make various state changes here but don't have to do so in a
// setState() callback because we are called during layout and all
// we're updating is the new offset, which we are providing to the
// render object via our return value.
didUpdateScrollBehavior(scrollBehavior.updateExtents(
contentExtent: dimensions.contentSize.height,
containerExtent: dimensions.containerSize.height,
scrollOffset: scrollOffset
));
updateGestureDetector();
return scrollOffsetToPixelDelta(scrollOffset);
}
@override
Widget buildContent(BuildContext context) {
return new MixedViewport(
startOffset: scrollOffset,
builder: config.builder,
token: config.token,
onInvalidatorAvailable: config.onInvalidatorAvailable,
onPaintOffsetUpdateNeeded: _handlePaintOffsetUpdateNeeded
);
}
}
...@@ -27,7 +27,6 @@ export 'src/widgets/lazy_block.dart'; ...@@ -27,7 +27,6 @@ export 'src/widgets/lazy_block.dart';
export 'src/widgets/locale_query.dart'; export 'src/widgets/locale_query.dart';
export 'src/widgets/media_query.dart'; export 'src/widgets/media_query.dart';
export 'src/widgets/mimic.dart'; export 'src/widgets/mimic.dart';
export 'src/widgets/mixed_viewport.dart';
export 'src/widgets/modal_barrier.dart'; export 'src/widgets/modal_barrier.dart';
export 'src/widgets/navigator.dart'; export 'src/widgets/navigator.dart';
export 'src/widgets/notification_listener.dart'; export 'src/widgets/notification_listener.dart';
......
...@@ -9,7 +9,7 @@ import 'package:test/test.dart'; ...@@ -9,7 +9,7 @@ import 'package:test/test.dart';
import 'test_widgets.dart'; import 'test_widgets.dart';
void main() { void main() {
test('MixedViewport mount/dismount smoke test', () { test('LazyBlockViewport mount/dismount smoke test', () {
testWidgets((WidgetTester tester) { testWidgets((WidgetTester tester) {
List<int> callbackTracker = <int>[]; List<int> callbackTracker = <int>[];
...@@ -18,15 +18,15 @@ void main() { ...@@ -18,15 +18,15 @@ void main() {
Widget builder() { Widget builder() {
return new FlipWidget( return new FlipWidget(
left: new MixedViewport( left: new LazyBlockViewport(
builder: (BuildContext context, int i) { delegate: new LazyBlockBuilder(builder: (BuildContext context, int i) {
callbackTracker.add(i); callbackTracker.add(i);
return new Container( return new Container(
key: new ValueKey<int>(i), key: new ValueKey<int>(i),
height: 100.0, height: 100.0,
child: new Text("$i") child: new Text("$i")
); );
}, }),
startOffset: 0.0 startOffset: 0.0
), ),
right: new Text('Not Today') right: new Text('Not Today')
...@@ -54,7 +54,7 @@ void main() { ...@@ -54,7 +54,7 @@ void main() {
}); });
}); });
test('MixedViewport vertical', () { test('LazyBlockViewport vertical', () {
testWidgets((WidgetTester tester) { testWidgets((WidgetTester tester) {
List<int> callbackTracker = <int>[]; List<int> callbackTracker = <int>[];
...@@ -76,8 +76,8 @@ void main() { ...@@ -76,8 +76,8 @@ void main() {
Widget builder() { Widget builder() {
return new FlipWidget( return new FlipWidget(
left: new MixedViewport( left: new LazyBlockViewport(
builder: itemBuilder, delegate: new LazyBlockBuilder(builder: itemBuilder),
startOffset: offset startOffset: offset
), ),
right: new Text('Not Today') right: new Text('Not Today')
...@@ -86,23 +86,27 @@ void main() { ...@@ -86,23 +86,27 @@ void main() {
tester.pumpWidget(builder()); tester.pumpWidget(builder());
// 0 is built to find its width // 0 is built to find its height
expect(callbackTracker, equals([0, 1, 2, 3, 4])); expect(callbackTracker, equals([0, 1, 2, 3, 4]));
callbackTracker.clear(); callbackTracker.clear();
offset = 400.0; // now only 3 should fit, numbered 2-4. offset = 400.0; // now only 3 should fit, numbered 2-4.
tester.pumpWidget(builder()); tester.pumpWidget(builder());
// 0 and 1 aren't built, we know their size and nothing else changed // We build all the children to find their new size.
expect(callbackTracker, equals([2, 3, 4])); expect(callbackTracker, equals([0, 1, 2, 3, 4]));
callbackTracker.clear();
tester.pumpWidget(builder());
// 0 isn't built because they're not visible.
expect(callbackTracker, equals([1, 2, 3, 4]));
callbackTracker.clear(); callbackTracker.clear();
}); });
}); });
test('MixedViewport horizontal', () { test('LazyBlockViewport horizontal', () {
testWidgets((WidgetTester tester) { testWidgets((WidgetTester tester) {
List<int> callbackTracker = <int>[]; List<int> callbackTracker = <int>[];
...@@ -124,10 +128,10 @@ void main() { ...@@ -124,10 +128,10 @@ void main() {
Widget builder() { Widget builder() {
return new FlipWidget( return new FlipWidget(
left: new MixedViewport( left: new LazyBlockViewport(
builder: itemBuilder, delegate: new LazyBlockBuilder(builder: itemBuilder),
startOffset: offset, startOffset: offset,
direction: Axis.horizontal mainAxis: Axis.horizontal
), ),
right: new Text('Not Today') right: new Text('Not Today')
); );
...@@ -144,14 +148,19 @@ void main() { ...@@ -144,14 +148,19 @@ void main() {
tester.pumpWidget(builder()); tester.pumpWidget(builder());
// 0 and 1 aren't built, we know their size and nothing else changed // We build all the children to find their new size.
expect(callbackTracker, equals([2, 3, 4, 5])); expect(callbackTracker, equals([0, 1, 2, 3, 4, 5]));
callbackTracker.clear();
tester.pumpWidget(builder());
// 0 isn't built because they're not visible.
expect(callbackTracker, equals([1, 2, 3, 4, 5]));
callbackTracker.clear(); callbackTracker.clear();
}); });
}); });
test('MixedViewport reinvoke builders', () { test('LazyBlockViewport reinvoke builders', () {
testWidgets((WidgetTester tester) { testWidgets((WidgetTester tester) {
List<int> callbackTracker = <int>[]; List<int> callbackTracker = <int>[];
List<String> text = <String>[]; List<String> text = <String>[];
...@@ -173,8 +182,8 @@ void main() { ...@@ -173,8 +182,8 @@ void main() {
}; };
Widget builder() { Widget builder() {
return new MixedViewport( return new LazyBlockViewport(
builder: itemBuilder, delegate: new LazyBlockBuilder(builder: itemBuilder),
startOffset: 0.0 startOffset: 0.0
); );
} }
...@@ -197,7 +206,7 @@ void main() { ...@@ -197,7 +206,7 @@ void main() {
}); });
}); });
test('MixedViewport reinvoke builders', () { test('LazyBlockViewport reinvoke builders', () {
testWidgets((WidgetTester tester) { testWidgets((WidgetTester tester) {
StateSetter setState; StateSetter setState;
ThemeData themeData = new ThemeData.light(); ThemeData themeData = new ThemeData.light();
...@@ -214,7 +223,9 @@ void main() { ...@@ -214,7 +223,9 @@ void main() {
); );
}; };
Widget viewport = new MixedViewport(builder: itemBuilder); Widget viewport = new LazyBlockViewport(
delegate: new LazyBlockBuilder(builder: itemBuilder)
);
tester.pumpWidget( tester.pumpWidget(
new StatefulBuilder( new StatefulBuilder(
......
...@@ -28,7 +28,7 @@ Widget buildFrame() { ...@@ -28,7 +28,7 @@ Widget buildFrame() {
} }
void main() { void main() {
test('MixedViewport is a build function (smoketest)', () { test('LazyBlock is a build function (smoketest)', () {
testWidgets((WidgetTester tester) { testWidgets((WidgetTester tester) {
tester.pumpWidget(buildFrame()); tester.pumpWidget(buildFrame());
expect(tester.findText('0'), isNotNull); expect(tester.findText('0'), isNotNull);
......
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