Add a sliver-based ScrollView (#7627)

This patch introduces ScrollView, which is a convenience widget for using a
SliverBlock. This patch also switches a number of tests from Block to
ScrollView. Once we support more features of block (e.g., padding and
shrinkwrapping), we'll be able to move over more clients.
diff --git a/packages/flutter/lib/src/material/material.dart b/packages/flutter/lib/src/material/material.dart
index 680b717..cdd8a52 100644
--- a/packages/flutter/lib/src/material/material.dart
+++ b/packages/flutter/lib/src/material/material.dart
@@ -376,8 +376,8 @@
     assert(referenceBox.attached);
     assert(!_debugDisposed);
     // find the chain of renderers from us to the feature's referenceBox
-    final List<RenderBox> descendants = <RenderBox>[referenceBox];
-    RenderBox node = referenceBox;
+    final List<RenderObject> descendants = <RenderObject>[referenceBox];
+    RenderObject node = referenceBox;
     while (node != _controller) {
       node = node.parent;
       assert(node != null);
diff --git a/packages/flutter/lib/src/rendering/sliver.dart b/packages/flutter/lib/src/rendering/sliver.dart
index 39c388a..99fb57c 100644
--- a/packages/flutter/lib/src/rendering/sliver.dart
+++ b/packages/flutter/lib/src/rendering/sliver.dart
@@ -999,14 +999,19 @@
   /// Calling this for a child that is not visible is not valid.
   @protected
   void applyPaintTransformForBoxChild(RenderBox child, Matrix4 transform) {
-    final double sign = _getRightWayUp(constraints) ? 1.0 : -1.0;
+    final bool rightWayUp = _getRightWayUp(constraints);
+    double delta = childPosition(child);
     assert(constraints.axis != null);
     switch (constraints.axis) {
       case Axis.horizontal:
-        transform.translate(childPosition(child) * sign, 0.0);
+        if (!rightWayUp)
+          delta = geometry.paintExtent - child.size.width - delta;
+        transform.translate(delta, 0.0);
         break;
       case Axis.vertical:
-        transform.translate(0.0, childPosition(child) * sign);
+        if (!rightWayUp)
+          delta = geometry.paintExtent - child.size.height - delta;
+        transform.translate(0.0, delta);
         break;
     }
   }
diff --git a/packages/flutter/lib/src/rendering/sliver_block.dart b/packages/flutter/lib/src/rendering/sliver_block.dart
index 1a9a031..e89fbda 100644
--- a/packages/flutter/lib/src/rendering/sliver_block.dart
+++ b/packages/flutter/lib/src/rendering/sliver_block.dart
@@ -506,10 +506,8 @@
   bool hitTestChildren(HitTestResult result, { @required double mainAxisPosition, @required double crossAxisPosition }) {
     RenderBox child = lastChild;
     while (child != null) {
-      if (child != null) {
-        if (hitTestBoxChild(result, child, mainAxisPosition: mainAxisPosition, crossAxisPosition: crossAxisPosition))
-          return true;
-      }
+      if (hitTestBoxChild(result, child, mainAxisPosition: mainAxisPosition, crossAxisPosition: crossAxisPosition))
+        return true;
       child = childBefore(child);
     }
     return false;
@@ -517,46 +515,12 @@
 
   @override
   double childPosition(RenderBox child) {
-    return offsetOf(child);
+    return offsetOf(child) - constraints.scrollOffset;
   }
 
-  // TODO(ianh): There's a lot of duplicate code in the next two functions,
-  // but I don't see a good way to avoid it, since both functions are hot.
-
   @override
   void applyPaintTransform(RenderObject child, Matrix4 transform) {
-    // coordinate system origin here is at the top-left corner, regardless of our axis direction.
-    // originOffset gives us the delta from the real origin to the origin in the axis direction.
-    Offset unitOffset, originOffset;
-    bool addExtent;
-    switch (applyGrowthDirectionToAxisDirection(constraints.axisDirection, constraints.growthDirection)) {
-      case AxisDirection.up:
-        unitOffset = const Offset(0.0, -1.0);
-        originOffset = new Offset(0.0, geometry.paintExtent);
-        addExtent = true;
-        break;
-      case AxisDirection.right:
-        unitOffset = const Offset(1.0, 0.0);
-        originOffset = Offset.zero;
-        addExtent = false;
-        break;
-      case AxisDirection.down:
-        unitOffset = const Offset(0.0, 1.0);
-        originOffset = Offset.zero;
-        addExtent = false;
-        break;
-      case AxisDirection.left:
-        unitOffset = const Offset(-1.0, 0.0);
-        originOffset = new Offset(geometry.paintExtent, 0.0);
-        addExtent = true;
-        break;
-    }
-    assert(unitOffset != null);
-    assert(addExtent != null);
-    Offset childOffset = originOffset + unitOffset * (offsetOf(child) - constraints.scrollOffset);
-    if (addExtent)
-      childOffset += unitOffset * paintExtentOf(child);
-    transform.translate(childOffset.dx, childOffset.dy);
+    applyPaintTransformForBoxChild(child, transform);
   }
 
   @override
@@ -593,7 +557,7 @@
     assert(addExtent != null);
     RenderBox child = firstChild;
     while (child != null) {
-      Offset childOffset = originOffset + unitOffset * (offsetOf(child) - constraints.scrollOffset);
+      Offset childOffset = originOffset + unitOffset * childPosition(child);
       if (addExtent)
         childOffset += unitOffset * paintExtentOf(child);
       context.paintChild(child, childOffset);
diff --git a/packages/flutter/lib/src/widgets/block.dart b/packages/flutter/lib/src/widgets/block.dart
index c12ef4b..27b6431 100644
--- a/packages/flutter/lib/src/widgets/block.dart
+++ b/packages/flutter/lib/src/widgets/block.dart
@@ -10,6 +10,56 @@
 
 import 'framework.dart';
 import 'basic.dart';
+import 'scrollable.dart';
+
+class ScrollView extends StatelessWidget {
+  ScrollView({
+    Key key,
+    this.scrollDirection: Axis.vertical,
+    this.anchor: 0.0,
+    this.initialScrollOffset: 0.0,
+    this.scrollBehavior,
+    this.center,
+    this.children,
+  }) : super(key: key);
+
+  final Axis scrollDirection;
+
+  final double anchor;
+
+  final double initialScrollOffset;
+
+  final ScrollBehavior2 scrollBehavior;
+
+  final Key center;
+
+  final List<Widget> children;
+
+  AxisDirection _getDirection(BuildContext context) {
+    // TODO(abarth): Consider reading direction.
+    switch (scrollDirection) {
+      case Axis.horizontal:
+        return AxisDirection.right;
+      case Axis.vertical:
+        return AxisDirection.down;
+    }
+    return null;
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return new Scrollable2(
+      axisDirection: _getDirection(context),
+      anchor: anchor,
+      initialScrollOffset: initialScrollOffset,
+      scrollBehavior: scrollBehavior,
+      center: center,
+      children: <Widget>[
+        new SliverBlock(delegate: new SliverBlockChildListDelegate(children)),
+      ],
+    );
+  }
+}
 
 abstract class SliverBlockDelegate {
   /// Abstract const constructor. This constructor enables subclasses to provide
diff --git a/packages/flutter/lib/src/widgets/gesture_detector.dart b/packages/flutter/lib/src/widgets/gesture_detector.dart
index bfb852a..51bbe59 100644
--- a/packages/flutter/lib/src/widgets/gesture_detector.dart
+++ b/packages/flutter/lib/src/widgets/gesture_detector.dart
@@ -509,7 +509,7 @@
         if (recognizer.onUpdate != null)
           recognizer.onUpdate(updateDetails);
         if (recognizer.onEnd != null)
-          recognizer.onEnd(new DragEndDetails());
+          recognizer.onEnd(new DragEndDetails(primaryVelocity: 0.0));
         return;
       }
     }
@@ -536,7 +536,7 @@
         if (recognizer.onUpdate != null)
           recognizer.onUpdate(updateDetails);
         if (recognizer.onEnd != null)
-          recognizer.onEnd(new DragEndDetails());
+          recognizer.onEnd(new DragEndDetails(primaryVelocity: 0.0));
         return;
       }
     }
diff --git a/packages/flutter/lib/src/widgets/scroll_absolute.dart b/packages/flutter/lib/src/widgets/scroll_absolute.dart
index 6507673..3c92e60 100644
--- a/packages/flutter/lib/src/widgets/scroll_absolute.dart
+++ b/packages/flutter/lib/src/widgets/scroll_absolute.dart
@@ -608,7 +608,7 @@
   }
 
   void _end() {
-    position.beginIdleActivity();
+    position?.beginIdleActivity();
   }
 
   @override
diff --git a/packages/flutter/lib/src/widgets/scrollable.dart b/packages/flutter/lib/src/widgets/scrollable.dart
index d4e6912..c4acaa9 100644
--- a/packages/flutter/lib/src/widgets/scrollable.dart
+++ b/packages/flutter/lib/src/widgets/scrollable.dart
@@ -304,7 +304,9 @@
   bool get isScrolling;
 
   @mustCallSuper
-  void dispose() { }
+  void dispose() {
+    _position = null;
+  }
 
   @override
   String toString() => '$runtimeType';
diff --git a/packages/flutter/test/material/about_test.dart b/packages/flutter/test/material/about_test.dart
index 325e7c9..6775ec2 100644
--- a/packages/flutter/test/material/about_test.dart
+++ b/packages/flutter/test/material/about_test.dart
@@ -18,7 +18,7 @@
             title: new Text('Home'),
           ),
           drawer: new Drawer(
-            child: new Block(
+            child: new ScrollView(
               children: <Widget>[
                 new AboutDrawerItem(
                   applicationVersion: '0.1.2',
diff --git a/packages/flutter/test/material/date_picker_test.dart b/packages/flutter/test/material/date_picker_test.dart
index cbe534a..9ad4c25 100644
--- a/packages/flutter/test/material/date_picker_test.dart
+++ b/packages/flutter/test/material/date_picker_test.dart
@@ -19,22 +19,20 @@
               builder: (BuildContext context, StateSetter setState) {
                 return new Positioned(
                   width: 400.0,
-                  child: new Block(
-                    children: <Widget>[
-                      new Material(
-                        child: new MonthPicker(
-                          firstDate: new DateTime(0),
-                          lastDate: new DateTime(9999),
-                          key: _datePickerKey,
-                          selectedDate: _selectedDate,
-                          onChanged: (DateTime value) {
-                            setState(() {
-                              _selectedDate = value;
-                            });
-                          }
-                        )
+                  child: new SingleChildScrollView(
+                    child: new Material(
+                      child: new MonthPicker(
+                        firstDate: new DateTime(0),
+                        lastDate: new DateTime(9999),
+                        key: _datePickerKey,
+                        selectedDate: _selectedDate,
+                        onChanged: (DateTime value) {
+                          setState(() {
+                            _selectedDate = value;
+                          });
+                        }
                       )
-                    ]
+                    )
                   )
                 );
               }
@@ -91,15 +89,13 @@
                 return new IntrinsicWidth(
                   child: new IntrinsicHeight(
                     child: new Material(
-                      child: new Block(
-                        children: <Widget>[
-                          new MonthPicker(
-                            firstDate: new DateTime(0),
-                            lastDate: new DateTime(9999),
-                            onChanged: (DateTime value) { },
-                            selectedDate: new DateTime(2000, DateTime.JANUARY, 1)
-                          )
-                        ]
+                      child: new SingleChildScrollView(
+                        child: new MonthPicker(
+                          firstDate: new DateTime(0),
+                          lastDate: new DateTime(9999),
+                          onChanged: (DateTime value) { },
+                          selectedDate: new DateTime(2000, DateTime.JANUARY, 1)
+                        )
                       )
                     )
                   )
diff --git a/packages/flutter/test/material/drawer_test.dart b/packages/flutter/test/material/drawer_test.dart
index 4b4cd6f..98e8925 100644
--- a/packages/flutter/test/material/drawer_test.dart
+++ b/packages/flutter/test/material/drawer_test.dart
@@ -12,7 +12,7 @@
     await tester.pumpWidget(
       new Scaffold(
         drawer: new Drawer(
-          child: new Block(
+          child: new ScrollView(
             children: <Widget>[
               new DrawerHeader(
                 child: new Container(
diff --git a/packages/flutter/test/widgets/container_test.dart b/packages/flutter/test/widgets/container_test.dart
index ec250f9..3f195e6 100644
--- a/packages/flutter/test/widgets/container_test.dart
+++ b/packages/flutter/test/widgets/container_test.dart
@@ -50,6 +50,6 @@
   });
 
   testWidgets('Can be placed in an infinite box', (WidgetTester tester) async {
-    await tester.pumpWidget(new Block(children: <Widget>[new Container()]));
+    await tester.pumpWidget(new ScrollView(children: <Widget>[new Container()]));
   });
 }
diff --git a/packages/flutter/test/widgets/draggable_test.dart b/packages/flutter/test/widgets/draggable_test.dart
index cbcf02c..927bb74 100644
--- a/packages/flutter/test/widgets/draggable_test.dart
+++ b/packages/flutter/test/widgets/draggable_test.dart
@@ -312,7 +312,7 @@
     Point firstLocation, secondLocation, thirdLocation;
 
     await tester.pumpWidget(new MaterialApp(
-      home: new Block(
+      home: new ScrollView(
         children: <Widget>[
           new DragTarget<int>(
             builder: (BuildContext context, List<int> data, List<dynamic> rejects) {
@@ -409,7 +409,7 @@
     await gesture.up();
     await tester.pump();
     expect(events, equals(<String>[]));
-    expect(tester.getCenter(find.text('Target')).y, lessThan(0.0));
+    expect(find.text('Target'), findsNothing);
     events.clear();
   });
 
@@ -418,7 +418,7 @@
     Point firstLocation, secondLocation, thirdLocation;
 
     await tester.pumpWidget(new MaterialApp(
-      home: new Block(
+      home: new ScrollView(
         scrollDirection: Axis.horizontal,
         children: <Widget>[
           new DragTarget<int>(
@@ -516,7 +516,7 @@
     await gesture.up();
     await tester.pump();
     expect(events, equals(<String>[]));
-    expect(tester.getCenter(find.text('Target')).x, lessThan(0.0));
+    expect(find.text('Target'), findsNothing);
     events.clear();
   });
 
diff --git a/packages/flutter/test/widgets/form_test.dart b/packages/flutter/test/widgets/form_test.dart
index 7d8bd26..65fb2ff 100644
--- a/packages/flutter/test/widgets/form_test.dart
+++ b/packages/flutter/test/widgets/form_test.dart
@@ -149,7 +149,7 @@
             autovalidate: true,
             child: new Focus(
               key: focusKey,
-              child: new Block(
+              child: new ScrollView(
                 children: <Widget>[
                   new TextField(
                     key: fieldKey
diff --git a/packages/flutter/test/widgets/heroes_test.dart b/packages/flutter/test/widgets/heroes_test.dart
index 25fff3d..1c76377 100644
--- a/packages/flutter/test/widgets/heroes_test.dart
+++ b/packages/flutter/test/widgets/heroes_test.dart
@@ -11,31 +11,37 @@
 
 final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
   '/': (BuildContext context) => new Material(
-    child: new Block(children: <Widget>[
-      new Container(height: 100.0, width: 100.0),
-      new Card(child: new Hero(tag: 'a', child: new Container(height: 100.0, width: 100.0, key: firstKey))),
-      new Container(height: 100.0, width: 100.0),
-      new FlatButton(child: new Text('two'), onPressed: () => Navigator.pushNamed(context, '/two')),
-    ])
+    child: new ScrollView(
+      children: <Widget>[
+        new Container(height: 100.0, width: 100.0),
+        new Card(child: new Hero(tag: 'a', child: new Container(height: 100.0, width: 100.0, key: firstKey))),
+        new Container(height: 100.0, width: 100.0),
+        new FlatButton(child: new Text('two'), onPressed: () => Navigator.pushNamed(context, '/two')),
+      ]
+    )
   ),
   '/two': (BuildContext context) => new Material(
-    child: new Block(children: <Widget>[
-      new Container(height: 150.0, width: 150.0),
-      new Card(child: new Hero(tag: 'a', child: new Container(height: 150.0, width: 150.0, key: secondKey))),
-      new Container(height: 150.0, width: 150.0),
-      new FlatButton(child: new Text('three'), onPressed: () => Navigator.push(context, new ThreeRoute())),
-    ])
+    child: new ScrollView(
+      children: <Widget>[
+        new Container(height: 150.0, width: 150.0),
+        new Card(child: new Hero(tag: 'a', child: new Container(height: 150.0, width: 150.0, key: secondKey))),
+        new Container(height: 150.0, width: 150.0),
+        new FlatButton(child: new Text('three'), onPressed: () => Navigator.push(context, new ThreeRoute())),
+      ]
+    )
   ),
 };
 
 class ThreeRoute extends MaterialPageRoute<Null> {
   ThreeRoute() : super(builder: (BuildContext context) {
     return new Material(
-      child: new Block(children: <Widget>[
-        new Container(height: 200.0, width: 200.0),
-        new Card(child: new Hero(tag: 'a', child: new Container(height: 200.0, width: 200.0, key: thirdKey))),
-        new Container(height: 200.0, width: 200.0),
-      ])
+      child: new ScrollView(
+        children: <Widget>[
+          new Container(height: 200.0, width: 200.0),
+          new Card(child: new Hero(tag: 'a', child: new Container(height: 200.0, width: 200.0, key: thirdKey))),
+          new Container(height: 200.0, width: 200.0),
+        ]
+      )
     );
   });
 }
@@ -161,12 +167,16 @@
     MutatingRoute route = new MutatingRoute();
 
     await tester.pumpWidget(new MaterialApp(
-      home: new Material(child: new Block(children: <Widget>[
-        new Hero(tag: 'a', child: new Text('foo')),
-        new Builder(builder: (BuildContext context) {
-          return new FlatButton(child: new Text('two'), onPressed: () => Navigator.push(context, route));
-        })
-      ]))
+      home: new Material(
+        child: new ScrollView(
+          children: <Widget>[
+            new Hero(tag: 'a', child: new Text('foo')),
+            new Builder(builder: (BuildContext context) {
+              return new FlatButton(child: new Text('two'), onPressed: () => Navigator.push(context, route));
+            })
+          ]
+        )
+      )
     ));
 
     await tester.tap(find.text('two'));
diff --git a/packages/flutter/test/widgets/scroll_view_test.dart b/packages/flutter/test/widgets/scroll_view_test.dart
new file mode 100644
index 0000000..73762b8
--- /dev/null
+++ b/packages/flutter/test/widgets/scroll_view_test.dart
@@ -0,0 +1,98 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter_test/flutter_test.dart';
+import 'package:flutter/widgets.dart';
+
+const List<String> _kStates = const <String>[
+  'Alabama',
+  'Alaska',
+  'Arizona',
+  'Arkansas',
+  'California',
+  'Colorado',
+  'Connecticut',
+  'Delaware',
+  'Florida',
+  'Georgia',
+  'Hawaii',
+  'Idaho',
+  'Illinois',
+  'Indiana',
+  'Iowa',
+  'Kansas',
+  'Kentucky',
+  'Louisiana',
+  'Maine',
+  'Maryland',
+  'Massachusetts',
+  'Michigan',
+  'Minnesota',
+  'Mississippi',
+  'Missouri',
+  'Montana',
+  'Nebraska',
+  'Nevada',
+  'New Hampshire',
+  'New Jersey',
+  'New Mexico',
+  'New York',
+  'North Carolina',
+  'North Dakota',
+  'Ohio',
+  'Oklahoma',
+  'Oregon',
+  'Pennsylvania',
+  'Rhode Island',
+  'South Carolina',
+  'South Dakota',
+  'Tennessee',
+  'Texas',
+  'Utah',
+  'Vermont',
+  'Virginia',
+  'Washington',
+  'West Virginia',
+  'Wisconsin',
+  'Wyoming',
+];
+
+void main() {
+  testWidgets('ScrollView control test', (WidgetTester tester) async {
+    List<String> log = <String>[];
+
+    await tester.pumpWidget(new ClipRect(child: new ScrollView(
+      children: _kStates.map<Widget>((String state) {
+        return new GestureDetector(
+          onTap: () {
+            log.add(state);
+          },
+          child: new Container(
+            height: 200.0,
+            decoration: const BoxDecoration(
+              backgroundColor: const Color(0xFF0000FF),
+            ),
+            child: new Text(state),
+          ),
+        );
+      }).toList()
+    )));
+
+    await tester.tap(find.text('Alabama'));
+    expect(log, equals(<String>['Alabama']));
+    log.clear();
+
+    expect(find.text('Nevada'), findsNothing);
+
+    await tester.scroll(find.text('Alabama'), const Offset(0.0, -4000.0));
+    await tester.pump();
+
+    expect(find.text('Alabama'), findsNothing);
+    expect(tester.getCenter(find.text('Massachusetts')), equals(const Point(400.0, 100.0)));
+
+    await tester.tap(find.text('Massachusetts'));
+    expect(log, equals(<String>['Massachusetts']));
+    log.clear();
+  });
+}
diff --git a/packages/flutter/test/widgets/scrollable_dispose_test.dart b/packages/flutter/test/widgets/scrollable_dispose_test.dart
index ff61bdc..24aa922 100644
--- a/packages/flutter/test/widgets/scrollable_dispose_test.dart
+++ b/packages/flutter/test/widgets/scrollable_dispose_test.dart
@@ -13,11 +13,11 @@
     for (int i = 0; i < 250; i++)
       textWidgets.add(new Text('$i'));
     await tester.pumpWidget(new FlipWidget(
-      left: new Block(children: textWidgets),
+      left: new ScrollView(children: textWidgets),
       right: new Container()
     ));
 
-    await tester.fling(find.byType(Scrollable), const Offset(0.0, -200.0), 1000.0);
+    await tester.fling(find.byType(ScrollView), const Offset(0.0, -200.0), 1000.0);
     await tester.pump();
 
     tester.state<FlipWidgetState>(find.byType(FlipWidget)).flip();
diff --git a/packages/flutter/test/widgets/semantics_debugger_test.dart b/packages/flutter/test/widgets/semantics_debugger_test.dart
index 246582e..ce8be6f 100644
--- a/packages/flutter/test/widgets/semantics_debugger_test.dart
+++ b/packages/flutter/test/widgets/semantics_debugger_test.dart
@@ -126,20 +126,22 @@
     await tester.pumpWidget(
       new SemanticsDebugger(
         child: new Material(
-          child: new Block(children: <Widget>[
-            new RaisedButton(
-              onPressed: () {
-                log.add('top');
-              },
-              child: new Text('TOP'),
-            ),
-            new RaisedButton(
-              onPressed: () {
-                log.add('bottom');
-              },
-              child: new Text('BOTTOM'),
-            ),
-          ]),
+          child: new ScrollView(
+            children: <Widget>[
+              new RaisedButton(
+                onPressed: () {
+                  log.add('top');
+                },
+                child: new Text('TOP'),
+              ),
+              new RaisedButton(
+                onPressed: () {
+                  log.add('bottom');
+                },
+                child: new Text('BOTTOM'),
+              ),
+            ],
+          ),
         ),
       ),
     );
@@ -158,7 +160,7 @@
 
     await tester.pumpWidget(
       new SemanticsDebugger(
-        child: new Block(
+        child: new ScrollView(
           children: <Widget>[
             new Container(
               key: childKey,
@@ -173,22 +175,22 @@
 
     expect(tester.getTopLeft(find.byKey(childKey)).y, equals(0.0));
 
-    await tester.fling(find.byType(Block), const Offset(0.0, -200.0), 200.0);
+    await tester.fling(find.byType(ScrollView), const Offset(0.0, -200.0), 200.0);
     await tester.pump();
 
     expect(tester.getTopLeft(find.byKey(childKey)).y, equals(-480.0));
 
-    await tester.fling(find.byType(Block), const Offset(200.0, 0.0), 200.0);
+    await tester.fling(find.byType(ScrollView), const Offset(200.0, 0.0), 200.0);
     await tester.pump();
 
     expect(tester.getTopLeft(find.byKey(childKey)).y, equals(-480.0));
 
-    await tester.fling(find.byType(Block), const Offset(-200.0, 0.0), 200.0);
+    await tester.fling(find.byType(ScrollView), const Offset(-200.0, 0.0), 200.0);
     await tester.pump();
 
     expect(tester.getTopLeft(find.byKey(childKey)).y, equals(-480.0));
 
-    await tester.fling(find.byType(Block), const Offset(0.0, 200.0), 200.0);
+    await tester.fling(find.byType(ScrollView), const Offset(0.0, 200.0), 200.0);
     await tester.pump();
 
     expect(tester.getTopLeft(find.byKey(childKey)).y, equals(0.0));
@@ -245,7 +247,7 @@
     await tester.pumpWidget(
       new SemanticsDebugger(
         child: new Material(
-          child: new Block(
+          child: new ScrollView(
             children: <Widget>[
               new Checkbox(
                 key: keyTop,