From 458d0b3d21426aba9259537ae754f6d3e427a0d5 Mon Sep 17 00:00:00 2001 From: David Shuckerow Date: Tue, 28 Aug 2018 12:08:41 -0600 Subject: [PATCH] =?UTF-8?q?Update=20the=20reorderable=20list=20to=20use=20?= =?UTF-8?q?the=20primary=20scroll=20controller=20when=E2=80=A6=20(#20895)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lib/src/material/reorderable_list.dart | 8 +- .../test/material/reorderable_list_test.dart | 82 ++++++++++++++++++- 2 files changed, 85 insertions(+), 5 deletions(-) diff --git a/packages/flutter/lib/src/material/reorderable_list.dart b/packages/flutter/lib/src/material/reorderable_list.dart index 0f17f79197..06517e4ce5 100644 --- a/packages/flutter/lib/src/material/reorderable_list.dart +++ b/packages/flutter/lib/src/material/reorderable_list.dart @@ -173,7 +173,7 @@ class _ReorderableListContentState extends State<_ReorderableListContent> with T 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; @@ -231,6 +231,12 @@ class _ReorderableListContentState extends State<_ReorderableListContent> with T _entranceController.addStatusListener(_onEntranceStatusChanged); } + @override + void didChangeDependencies() { + _scrollController = PrimaryScrollController.of(context) ?? new ScrollController(); + super.didChangeDependencies(); + } + @override void dispose() { _entranceController.dispose(); diff --git a/packages/flutter/test/material/reorderable_list_test.dart b/packages/flutter/test/material/reorderable_list_test.dart index 592dd9efe1..df38b3b4da 100644 --- a/packages/flutter/test/material/reorderable_list_test.dart +++ b/packages/flutter/test/material/reorderable_list_test.dart @@ -142,9 +142,9 @@ void main() { )); 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 @@ void main() { 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 [ + 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 [ + 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 >[ + 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 getSemanticsActions(int index) { @@ -496,9 +570,9 @@ void main() { )); 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; }