Update the reorderable list to use the primary scroll controller when… (#20895)

diff --git a/packages/flutter/lib/src/material/reorderable_list.dart b/packages/flutter/lib/src/material/reorderable_list.dart
index 0f17f79..06517e4 100644
--- a/packages/flutter/lib/src/material/reorderable_list.dart
+++ b/packages/flutter/lib/src/material/reorderable_list.dart
@@ -173,7 +173,7 @@
   static const Duration _scrollAnimationDuration = Duration(milliseconds: 200);
 
   // Controls scrolls and measures scroll progress.
-  final ScrollController _scrollController = new ScrollController();
+  ScrollController _scrollController;
 
   // This controls the entrance of the dragging widget into a new place.
   AnimationController _entranceController;
@@ -232,6 +232,12 @@
   }
 
   @override
+  void didChangeDependencies() {
+    _scrollController = PrimaryScrollController.of(context) ?? new ScrollController();
+    super.didChangeDependencies();
+  }
+
+  @override
   void dispose() {
     _entranceController.dispose();
     _ghostController.dispose();
diff --git a/packages/flutter/test/material/reorderable_list_test.dart b/packages/flutter/test/material/reorderable_list_test.dart
index 592dd9e..df38b3b 100644
--- a/packages/flutter/test/material/reorderable_list_test.dart
+++ b/packages/flutter/test/material/reorderable_list_test.dart
@@ -142,9 +142,9 @@
         ));
 
         Element getContentElement() {
-          final SingleChildScrollView listScrollView = find.byType(SingleChildScrollView).evaluate().first.widget;
+          final SingleChildScrollView listScrollView = tester.widget(find.byType(SingleChildScrollView));
           final Widget scrollContents = listScrollView.child;
-          final Element contentElement = find.byElementPredicate((Element element) => element.widget == scrollContents).evaluate().first;
+          final Element contentElement = tester.element(find.byElementPredicate((Element element) => element.widget == scrollContents));
           return contentElement;
         }
 
@@ -224,6 +224,80 @@
         expect(findState(const Key('A')).checked, true);
       });
 
+      testWidgets('Uses the PrimaryScrollController when available', (WidgetTester tester) async {
+        final ScrollController primary = new ScrollController();
+        final Widget reorderableList = new ReorderableListView(
+          children: const <Widget>[
+            SizedBox(width: 100.0, height: 100.0, child: Text('C'), key: Key('C')),
+            SizedBox(width: 100.0, height: 100.0, child: Text('B'), key: Key('B')),
+            SizedBox(width: 100.0, height: 100.0, child: Text('A'), key: Key('A')),
+          ],
+          onReorder: (int oldIndex, int newIndex) {},
+        );
+
+        Widget buildWithScrollController(ScrollController controller) {
+          return new MaterialApp(
+            home: new PrimaryScrollController(
+              controller: controller,
+              child: new SizedBox(
+                height: 100.0,
+                width: 100.0,
+                child: reorderableList,
+              ),
+            ),
+          );
+        }
+
+        await tester.pumpWidget(buildWithScrollController(primary));
+        SingleChildScrollView scrollView = tester.widget(
+          find.byType(SingleChildScrollView),
+        );
+        expect(scrollView.controller, primary);
+
+        // Now try changing the primary scroll controller and checking that the scroll view gets updated.
+        final ScrollController primary2 = new ScrollController();
+        await tester.pumpWidget(buildWithScrollController(primary2));
+        scrollView = tester.widget(
+          find.byType(SingleChildScrollView),
+        );
+        expect(scrollView.controller, primary2);
+      });
+
+      testWidgets('Still builds when no PrimaryScrollController is available', (WidgetTester tester) async {
+        final Widget reorderableList = new ReorderableListView(
+          children: const <Widget>[
+            SizedBox(width: 100.0, height: 100.0, child: Text('C'), key: Key('C')),
+            SizedBox(width: 100.0, height: 100.0, child: Text('B'), key: Key('B')),
+            SizedBox(width: 100.0, height: 100.0, child: Text('A'), key: Key('A')),
+          ],
+          onReorder: (int oldIndex, int newIndex) {},
+        );
+        final Widget boilerplate = new Localizations(
+          locale: const Locale('en'),
+          delegates: const <LocalizationsDelegate<dynamic>>[
+            DefaultMaterialLocalizations.delegate,
+            DefaultWidgetsLocalizations.delegate,
+          ],
+          child:new SizedBox(
+            width: 100.0,
+            height: 100.0,
+            child: new Directionality(
+              textDirection: TextDirection.ltr,
+              child: reorderableList,
+            ),
+          ),
+        );
+        try {
+          await tester.pumpWidget(boilerplate);
+        } catch (e) {
+          fail('Expected no error, but got $e');
+        }
+        // Expect that we have build *a* ScrollController for use in the view.
+        final SingleChildScrollView scrollView = tester.widget(
+          find.byType(SingleChildScrollView),
+        );
+        expect(scrollView.controller, isNotNull);
+      });
 
       group('Accessibility (a11y/Semantics)', () {
         Map<CustomSemanticsAction, VoidCallback> getSemanticsActions(int index) {
@@ -496,9 +570,9 @@
         ));
 
         Element getContentElement() {
-          final SingleChildScrollView listScrollView = find.byType(SingleChildScrollView).evaluate().first.widget;
+          final SingleChildScrollView listScrollView = tester.widget(find.byType(SingleChildScrollView));
           final Widget scrollContents = listScrollView.child;
-          final Element contentElement = find.byElementPredicate((Element element) => element.widget == scrollContents).evaluate().first;
+          final Element contentElement = tester.element(find.byElementPredicate((Element element) => element.widget == scrollContents));
           return contentElement;
         }