Jaime Blasco

Merge branch 'primary-scroll'

@@ -53,8 +53,8 @@ class CupertinoSharePage extends StatelessWidget { @@ -53,8 +53,8 @@ class CupertinoSharePage extends StatelessWidget {
53 expand: true, 53 expand: true,
54 context: context, 54 context: context,
55 backgroundColor: Colors.transparent, 55 backgroundColor: Colors.transparent,
56 - builder: (context, scrollController) =>  
57 - PhotoShareBottomSheet(scrollController: scrollController), 56 + builder: (context) =>
  57 + PhotoShareBottomSheet(),
58 ); 58 );
59 }, 59 },
60 ), 60 ),
@@ -73,9 +73,9 @@ class CupertinoSharePage extends StatelessWidget { @@ -73,9 +73,9 @@ class CupertinoSharePage extends StatelessWidget {
73 } 73 }
74 74
75 class PhotoShareBottomSheet extends StatelessWidget { 75 class PhotoShareBottomSheet extends StatelessWidget {
76 - final ScrollController scrollController;  
77 76
78 - const PhotoShareBottomSheet({Key key, this.scrollController}) 77 +
  78 + const PhotoShareBottomSheet({Key key})
79 : super(key: key); 79 : super(key: key);
80 80
81 @override 81 @override
@@ -92,7 +92,7 @@ class PhotoShareBottomSheet extends StatelessWidget { @@ -92,7 +92,7 @@ class PhotoShareBottomSheet extends StatelessWidget {
92 appBar: appBar(context), 92 appBar: appBar(context),
93 body: CustomScrollView( 93 body: CustomScrollView(
94 physics: ClampingScrollPhysics(), 94 physics: ClampingScrollPhysics(),
95 - controller: scrollController, 95 + controller: ModalScrollController.of(context),
96 slivers: <Widget>[ 96 slivers: <Widget>[
97 SliverSafeArea( 97 SliverSafeArea(
98 bottom: false, 98 bottom: false,
@@ -51,11 +51,9 @@ class MyApp extends StatelessWidget { @@ -51,11 +51,9 @@ class MyApp extends StatelessWidget {
51 expand: true, 51 expand: true,
52 context: context, 52 context: context,
53 backgroundColor: Colors.transparent, 53 backgroundColor: Colors.transparent,
54 - builder: (context, scrollController) =>  
55 - Stack( 54 + builder: (context) => Stack(
56 children: <Widget>[ 55 children: <Widget>[
57 - ModalWithScroll(  
58 - scrollController: scrollController), 56 + ModalWithScroll(),
59 Positioned( 57 Positioned(
60 height: 40, 58 height: 40,
61 left: 40, 59 left: 40,
@@ -131,8 +129,7 @@ class _MyHomePageState extends State<MyHomePage> { @@ -131,8 +129,7 @@ class _MyHomePageState extends State<MyHomePage> {
131 expand: false, 129 expand: false,
132 context: context, 130 context: context,
133 backgroundColor: Colors.transparent, 131 backgroundColor: Colors.transparent,
134 - builder: (context, scrollController) =>  
135 - ModalFit(scrollController: scrollController), 132 + builder: (context) => ModalFit(),
136 )), 133 )),
137 ListTile( 134 ListTile(
138 title: Text('Bar Modal'), 135 title: Text('Bar Modal'),
@@ -140,9 +137,7 @@ class _MyHomePageState extends State<MyHomePage> { @@ -140,9 +137,7 @@ class _MyHomePageState extends State<MyHomePage> {
140 expand: true, 137 expand: true,
141 context: context, 138 context: context,
142 backgroundColor: Colors.transparent, 139 backgroundColor: Colors.transparent,
143 - builder: (context, scrollController) =>  
144 - ModalInsideModal(  
145 - scrollController: scrollController), 140 + builder: (context) => ModalInsideModal(),
146 )), 141 )),
147 ListTile( 142 ListTile(
148 title: Text('Avatar Modal'), 143 title: Text('Avatar Modal'),
@@ -150,16 +145,13 @@ class _MyHomePageState extends State<MyHomePage> { @@ -150,16 +145,13 @@ class _MyHomePageState extends State<MyHomePage> {
150 expand: true, 145 expand: true,
151 context: context, 146 context: context,
152 backgroundColor: Colors.transparent, 147 backgroundColor: Colors.transparent,
153 - builder: (context, scrollController) =>  
154 - ModalInsideModal(  
155 - scrollController: scrollController), 148 + builder: (context) => ModalInsideModal(),
156 )), 149 )),
157 ListTile( 150 ListTile(
158 title: Text('Float Modal'), 151 title: Text('Float Modal'),
159 onTap: () => showFloatingModalBottomSheet( 152 onTap: () => showFloatingModalBottomSheet(
160 context: context, 153 context: context,
161 - builder: (context, scrollController) =>  
162 - ModalFit(scrollController: scrollController), 154 + builder: (context) => ModalFit(),
163 )), 155 )),
164 ListTile( 156 ListTile(
165 title: Text('Cupertino Modal fit'), 157 title: Text('Cupertino Modal fit'),
@@ -167,8 +159,7 @@ class _MyHomePageState extends State<MyHomePage> { @@ -167,8 +159,7 @@ class _MyHomePageState extends State<MyHomePage> {
167 expand: false, 159 expand: false,
168 context: context, 160 context: context,
169 backgroundColor: Colors.transparent, 161 backgroundColor: Colors.transparent,
170 - builder: (context, scrollController) =>  
171 - ModalFit(scrollController: scrollController), 162 + builder: (context) => ModalFit(),
172 )), 163 )),
173 section('COMPLEX CASES'), 164 section('COMPLEX CASES'),
174 ListTile( 165 ListTile(
@@ -177,8 +168,7 @@ class _MyHomePageState extends State<MyHomePage> { @@ -177,8 +168,7 @@ class _MyHomePageState extends State<MyHomePage> {
177 expand: true, 168 expand: true,
178 context: context, 169 context: context,
179 backgroundColor: Colors.transparent, 170 backgroundColor: Colors.transparent,
180 - builder: (context, scrollController) =>  
181 - ModalFit(scrollController: scrollController), 171 + builder: (context) => ModalFit(),
182 )), 172 )),
183 ListTile( 173 ListTile(
184 title: Text('Reverse list'), 174 title: Text('Reverse list'),
@@ -186,10 +176,8 @@ class _MyHomePageState extends State<MyHomePage> { @@ -186,10 +176,8 @@ class _MyHomePageState extends State<MyHomePage> {
186 expand: true, 176 expand: true,
187 context: context, 177 context: context,
188 backgroundColor: Colors.transparent, 178 backgroundColor: Colors.transparent,
189 - builder: (context, scrollController) =>  
190 - ModalInsideModal(  
191 - scrollController: scrollController,  
192 - reverse: true), 179 + builder: (context) =>
  180 + ModalInsideModal(reverse: true),
193 )), 181 )),
194 ListTile( 182 ListTile(
195 title: Text('Cupertino Modal inside modal'), 183 title: Text('Cupertino Modal inside modal'),
@@ -197,9 +185,7 @@ class _MyHomePageState extends State<MyHomePage> { @@ -197,9 +185,7 @@ class _MyHomePageState extends State<MyHomePage> {
197 expand: true, 185 expand: true,
198 context: context, 186 context: context,
199 backgroundColor: Colors.transparent, 187 backgroundColor: Colors.transparent,
200 - builder: (context, scrollController) =>  
201 - ModalInsideModal(  
202 - scrollController: scrollController), 188 + builder: (context) => ModalInsideModal(),
203 )), 189 )),
204 ListTile( 190 ListTile(
205 title: Text('Cupertino Modal with inside navigation'), 191 title: Text('Cupertino Modal with inside navigation'),
@@ -207,9 +193,7 @@ class _MyHomePageState extends State<MyHomePage> { @@ -207,9 +193,7 @@ class _MyHomePageState extends State<MyHomePage> {
207 expand: true, 193 expand: true,
208 context: context, 194 context: context,
209 backgroundColor: Colors.transparent, 195 backgroundColor: Colors.transparent,
210 - builder: (context, scrollController) =>  
211 - ModalWithNavigator(  
212 - scrollController: scrollController), 196 + builder: (context) => ModalWithNavigator(),
213 )), 197 )),
214 ListTile( 198 ListTile(
215 title: 199 title:
@@ -218,9 +202,8 @@ class _MyHomePageState extends State<MyHomePage> { @@ -218,9 +202,8 @@ class _MyHomePageState extends State<MyHomePage> {
218 expand: true, 202 expand: true,
219 context: context, 203 context: context,
220 backgroundColor: Colors.transparent, 204 backgroundColor: Colors.transparent,
221 - builder: (context, scrollController) =>  
222 - ComplexModal(  
223 - scrollController: scrollController), 205 + builder: (context) =>
  206 + ComplexModal(),
224 )), 207 )),
225 ListTile( 208 ListTile(
226 title: Text('Modal with WillPopScope'), 209 title: Text('Modal with WillPopScope'),
@@ -228,18 +211,16 @@ class _MyHomePageState extends State<MyHomePage> { @@ -228,18 +211,16 @@ class _MyHomePageState extends State<MyHomePage> {
228 expand: true, 211 expand: true,
229 context: context, 212 context: context,
230 backgroundColor: Colors.transparent, 213 backgroundColor: Colors.transparent,
231 - builder: (context, scrollController) =>  
232 - ModalWillScope(  
233 - scrollController: scrollController), 214 + builder: (context) =>
  215 + ModalWillScope(),
234 )), 216 )),
235 ListTile( 217 ListTile(
236 title: Text('Modal with Nested Scroll'), 218 title: Text('Modal with Nested Scroll'),
237 onTap: () => showCupertinoModalBottomSheet( 219 onTap: () => showCupertinoModalBottomSheet(
238 expand: true, 220 expand: true,
239 context: context, 221 context: context,
240 - builder: (context, scrollController) =>  
241 - NestedScrollModal(  
242 - scrollController: scrollController), 222 + builder: (context) =>
  223 + NestedScrollModal(),
243 )), 224 )),
244 ListTile( 225 ListTile(
245 title: Text('Modal with PageView'), 226 title: Text('Modal with PageView'),
@@ -69,7 +69,7 @@ class AvatarBottomSheet extends StatelessWidget { @@ -69,7 +69,7 @@ class AvatarBottomSheet extends StatelessWidget {
69 69
70 Future<T> showAvatarModalBottomSheet<T>({ 70 Future<T> showAvatarModalBottomSheet<T>({
71 @required BuildContext context, 71 @required BuildContext context,
72 - @required ScrollWidgetBuilder builder, 72 + @required WidgetBuilder builder,
73 Color backgroundColor, 73 Color backgroundColor,
74 double elevation, 74 double elevation,
75 ShapeBorder shape, 75 ShapeBorder shape,
@@ -27,7 +27,7 @@ class FloatingModal extends StatelessWidget { @@ -27,7 +27,7 @@ class FloatingModal extends StatelessWidget {
27 27
28 Future<T> showFloatingModalBottomSheet<T>({ 28 Future<T> showFloatingModalBottomSheet<T>({
29 @required BuildContext context, 29 @required BuildContext context,
30 - @required ScrollWidgetBuilder builder, 30 + @required WidgetBuilder builder,
31 Color backgroundColor, 31 Color backgroundColor,
32 }) async { 32 }) async {
33 final result = await showCustomModalBottomSheet( 33 final result = await showCustomModalBottomSheet(
1 import 'package:flutter/cupertino.dart'; 1 import 'package:flutter/cupertino.dart';
2 import 'package:flutter/material.dart'; 2 import 'package:flutter/material.dart';
  3 +import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
3 4
4 class ComplexModal extends StatelessWidget { 5 class ComplexModal extends StatelessWidget {
5 - final ScrollController scrollController;  
6 -  
7 - const ComplexModal({Key key, this.scrollController}) : super(key: key); 6 + const ComplexModal({Key key}) : super(key: key);
8 7
9 @override 8 @override
10 Widget build(BuildContext context) { 9 Widget build(BuildContext context) {
@@ -46,7 +45,7 @@ class ComplexModal extends StatelessWidget { @@ -46,7 +45,7 @@ class ComplexModal extends StatelessWidget {
46 bottom: false, 45 bottom: false,
47 child: ListView( 46 child: ListView(
48 shrinkWrap: true, 47 shrinkWrap: true,
49 - controller: scrollController, 48 + controller: ModalScrollController.of(context),
50 children: ListTile.divideTiles( 49 children: ListTile.divideTiles(
51 context: context, 50 context: context,
52 tiles: List.generate( 51 tiles: List.generate(
@@ -2,9 +2,9 @@ import 'package:flutter/cupertino.dart'; @@ -2,9 +2,9 @@ import 'package:flutter/cupertino.dart';
2 import 'package:flutter/material.dart'; 2 import 'package:flutter/material.dart';
3 3
4 class ModalFit extends StatelessWidget { 4 class ModalFit extends StatelessWidget {
5 - final ScrollController scrollController;  
6 5
7 - const ModalFit({Key key, this.scrollController}) : super(key: key); 6 +
  7 + const ModalFit({Key key}) : super(key: key);
8 8
9 @override 9 @override
10 Widget build(BuildContext context) { 10 Widget build(BuildContext context) {
@@ -3,11 +3,9 @@ import 'package:flutter/material.dart'; @@ -3,11 +3,9 @@ import 'package:flutter/material.dart';
3 import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; 3 import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
4 4
5 class ModalInsideModal extends StatelessWidget { 5 class ModalInsideModal extends StatelessWidget {
6 - final ScrollController scrollController;  
7 final bool reverse; 6 final bool reverse;
8 7
9 - const ModalInsideModal({Key key, this.scrollController, this.reverse = false})  
10 - : super(key: key); 8 + const ModalInsideModal({Key key, this.reverse = false}) : super(key: key);
11 9
12 @override 10 @override
13 Widget build(BuildContext context) { 11 Widget build(BuildContext context) {
@@ -20,7 +18,7 @@ class ModalInsideModal extends StatelessWidget { @@ -20,7 +18,7 @@ class ModalInsideModal extends StatelessWidget {
20 child: ListView( 18 child: ListView(
21 reverse: reverse, 19 reverse: reverse,
22 shrinkWrap: true, 20 shrinkWrap: true,
23 - controller: scrollController, 21 + controller: ModalScrollController.of(context),
24 physics: ClampingScrollPhysics(), 22 physics: ClampingScrollPhysics(),
25 children: ListTile.divideTiles( 23 children: ListTile.divideTiles(
26 context: context, 24 context: context,
@@ -33,10 +31,8 @@ class ModalInsideModal extends StatelessWidget { @@ -33,10 +31,8 @@ class ModalInsideModal extends StatelessWidget {
33 isDismissible: false, 31 isDismissible: false,
34 context: context, 32 context: context,
35 backgroundColor: Colors.transparent, 33 backgroundColor: Colors.transparent,
36 - builder: (context, scrollController) =>  
37 - ModalInsideModal(  
38 - scrollController: scrollController,  
39 - reverse: reverse), 34 + builder: (context) =>
  35 + ModalInsideModal(reverse: reverse),
40 )), 36 )),
41 )).toList(), 37 )).toList(),
42 ), 38 ),
@@ -2,9 +2,9 @@ import 'package:flutter/cupertino.dart'; @@ -2,9 +2,9 @@ import 'package:flutter/cupertino.dart';
2 import 'package:flutter/material.dart'; 2 import 'package:flutter/material.dart';
3 3
4 class ModalWillScope extends StatelessWidget { 4 class ModalWillScope extends StatelessWidget {
5 - final ScrollController scrollController;  
6 5
7 - const ModalWillScope({Key key, this.scrollController}) : super(key: key); 6 +
  7 + const ModalWillScope({Key key}) : super(key: key);
8 8
9 @override 9 @override
10 Widget build(BuildContext context) { 10 Widget build(BuildContext context) {
1 import 'package:flutter/cupertino.dart'; 1 import 'package:flutter/cupertino.dart';
2 import 'package:flutter/material.dart'; 2 import 'package:flutter/material.dart';
  3 +import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
3 4
4 class ModalWithNavigator extends StatelessWidget { 5 class ModalWithNavigator extends StatelessWidget {
5 - final ScrollController scrollController;  
6 6
7 - const ModalWithNavigator({Key key, this.scrollController}) : super(key: key); 7 +
  8 + const ModalWithNavigator({Key key}) : super(key: key);
8 9
9 @override 10 @override
10 Widget build(BuildContext context) { 11 Widget build(BuildContext context) {
@@ -20,7 +21,7 @@ class ModalWithNavigator extends StatelessWidget { @@ -20,7 +21,7 @@ class ModalWithNavigator extends StatelessWidget {
20 bottom: false, 21 bottom: false,
21 child: ListView( 22 child: ListView(
22 shrinkWrap: true, 23 shrinkWrap: true,
23 - controller: scrollController, 24 + controller: ModalScrollController.of(context),
24 children: ListTile.divideTiles( 25 children: ListTile.divideTiles(
25 context: context, 26 context: context,
26 tiles: List.generate( 27 tiles: List.generate(
1 import 'package:flutter/cupertino.dart'; 1 import 'package:flutter/cupertino.dart';
2 import 'package:flutter/material.dart'; 2 import 'package:flutter/material.dart';
  3 +import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
3 4
4 class NestedScrollModal extends StatelessWidget { 5 class NestedScrollModal extends StatelessWidget {
5 - final ScrollController scrollController; 6 + const NestedScrollModal({Key key}) : super(key: key);
6 7
7 - const NestedScrollModal({Key key, this.scrollController}) : super(key: key);  
8 8
9 @override 9 @override
10 Widget build(BuildContext context) { 10 Widget build(BuildContext context) {
@@ -23,7 +23,7 @@ class NestedScrollModal extends StatelessWidget { @@ -23,7 +23,7 @@ class NestedScrollModal extends StatelessWidget {
23 ]; 23 ];
24 }, 24 },
25 body: ListView.builder( 25 body: ListView.builder(
26 - controller: scrollController, 26 + controller: ModalScrollController.of(context),
27 itemBuilder: (context, index) { 27 itemBuilder: (context, index) {
28 return Container( 28 return Container(
29 height: 100, 29 height: 100,
1 import 'package:flutter/cupertino.dart'; 1 import 'package:flutter/cupertino.dart';
2 import 'package:flutter/material.dart'; 2 import 'package:flutter/material.dart';
  3 +import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
3 4
4 class ModalWithScroll extends StatelessWidget { 5 class ModalWithScroll extends StatelessWidget {
5 - final ScrollController scrollController;  
6 -  
7 - const ModalWithScroll({Key key, this.scrollController}) : super(key: key); 6 + const ModalWithScroll({Key key}) : super(key: key);
8 7
9 @override 8 @override
10 Widget build(BuildContext context) { 9 Widget build(BuildContext context) {
  10 +
11 return Material( 11 return Material(
12 child: CupertinoPageScaffold( 12 child: CupertinoPageScaffold(
13 navigationBar: CupertinoNavigationBar( 13 navigationBar: CupertinoNavigationBar(
@@ -16,7 +16,7 @@ class ModalWithScroll extends StatelessWidget { @@ -16,7 +16,7 @@ class ModalWithScroll extends StatelessWidget {
16 bottom: false, 16 bottom: false,
17 child: ListView( 17 child: ListView(
18 shrinkWrap: true, 18 shrinkWrap: true,
19 - controller: scrollController, 19 + controller: ModalScrollController.of(context),
20 children: ListTile.divideTiles( 20 children: ListTile.divideTiles(
21 context: context, 21 context: context,
22 tiles: List.generate( 22 tiles: List.generate(
@@ -4,3 +4,4 @@ export 'src/material_with_modal_page_route.dart'; @@ -4,3 +4,4 @@ export 'src/material_with_modal_page_route.dart';
4 export 'src/bottom_sheets/cupertino_bottom_sheet.dart'; 4 export 'src/bottom_sheets/cupertino_bottom_sheet.dart';
5 export 'src/bottom_sheets/material_bottom_sheet.dart'; 5 export 'src/bottom_sheets/material_bottom_sheet.dart';
6 export 'src/bottom_sheets/bar_bottom_sheet.dart'; 6 export 'src/bottom_sheets/bar_bottom_sheet.dart';
  7 +export 'src/utils/modal_scroll_controller.dart';
@@ -9,7 +9,7 @@ import 'package:flutter/gestures.dart'; @@ -9,7 +9,7 @@ import 'package:flutter/gestures.dart';
9 import 'package:flutter/material.dart'; 9 import 'package:flutter/material.dart';
10 import 'package:flutter/scheduler.dart'; 10 import 'package:flutter/scheduler.dart';
11 import 'package:flutter/widgets.dart'; 11 import 'package:flutter/widgets.dart';
12 -import 'package:modal_bottom_sheet/src/utils/primary_scroll_status_bar.dart'; 12 +import 'package:modal_bottom_sheet/src/utils/scroll_to_top_status_bar.dart';
13 13
14 import 'package:modal_bottom_sheet/src/utils/bottom_sheet_suspended_curve.dart'; 14 import 'package:modal_bottom_sheet/src/utils/bottom_sheet_suspended_curve.dart';
15 15
@@ -20,9 +20,6 @@ const double _minFlingVelocity = 500.0; @@ -20,9 +20,6 @@ const double _minFlingVelocity = 500.0;
20 const double _closeProgressThreshold = 0.6; 20 const double _closeProgressThreshold = 0.6;
21 const double _willPopThreshold = 0.8; 21 const double _willPopThreshold = 0.8;
22 22
23 -typedef ScrollWidgetBuilder = Widget Function(  
24 - BuildContext context, ScrollController controller);  
25 -  
26 typedef WidgetWithChildBuilder = Widget Function( 23 typedef WidgetWithChildBuilder = Widget Function(
27 BuildContext context, Animation<double> animation, Widget child); 24 BuildContext context, Animation<double> animation, Widget child);
28 25
@@ -51,10 +48,10 @@ class ModalBottomSheet extends StatefulWidget { @@ -51,10 +48,10 @@ class ModalBottomSheet extends StatefulWidget {
51 this.scrollController, 48 this.scrollController,
52 this.expanded, 49 this.expanded,
53 @required this.onClosing, 50 @required this.onClosing,
54 - @required this.builder, 51 + @required this.child,
55 }) : assert(enableDrag != null), 52 }) : assert(enableDrag != null),
56 assert(onClosing != null), 53 assert(onClosing != null),
57 - assert(builder != null), 54 + assert(child != null),
58 super(key: key); 55 super(key: key);
59 56
60 /// The closeProgressThreshold parameter 57 /// The closeProgressThreshold parameter
@@ -100,7 +97,7 @@ class ModalBottomSheet extends StatefulWidget { @@ -100,7 +97,7 @@ class ModalBottomSheet extends StatefulWidget {
100 97
101 /// A builder for the contents of the sheet. 98 /// A builder for the contents of the sheet.
102 /// 99 ///
103 - final ScrollWidgetBuilder builder; 100 + final Widget child;
104 101
105 /// If true, the bottom sheet can be dragged up and down and dismissed by 102 /// If true, the bottom sheet can be dragged up and down and dismissed by
106 /// swiping downwards. 103 /// swiping downwards.
@@ -135,7 +132,7 @@ class _ModalBottomSheetState extends State<ModalBottomSheet> @@ -135,7 +132,7 @@ class _ModalBottomSheetState extends State<ModalBottomSheet>
135 with TickerProviderStateMixin { 132 with TickerProviderStateMixin {
136 final GlobalKey _childKey = GlobalKey(debugLabel: 'BottomSheet child'); 133 final GlobalKey _childKey = GlobalKey(debugLabel: 'BottomSheet child');
137 134
138 - ScrollController _scrollController; 135 + ScrollController get _scrollController => widget.scrollController;
139 136
140 AnimationController _bounceDragController; 137 AnimationController _bounceDragController;
141 138
@@ -267,6 +264,9 @@ class _ModalBottomSheetState extends State<ModalBottomSheet> @@ -267,6 +264,9 @@ class _ModalBottomSheetState extends State<ModalBottomSheet>
267 //Check if there is more than 1 attached ScrollController e.g. swiping page in PageView 264 //Check if there is more than 1 attached ScrollController e.g. swiping page in PageView
268 if (_scrollController.positions.length > 1) return; 265 if (_scrollController.positions.length > 1) return;
269 266
  267 + if (_scrollController !=
  268 + Scrollable.of(notification.context).widget.controller) return;
  269 +
270 final scrollPosition = _scrollController.position; 270 final scrollPosition = _scrollController.position;
271 271
272 if (scrollPosition.axis == Axis.horizontal) return; 272 if (scrollPosition.axis == Axis.horizontal) return;
@@ -277,14 +277,6 @@ class _ModalBottomSheetState extends State<ModalBottomSheet> @@ -277,14 +277,6 @@ class _ModalBottomSheetState extends State<ModalBottomSheet>
277 : scrollPosition.maxScrollExtent - scrollPosition.pixels; 277 : scrollPosition.maxScrollExtent - scrollPosition.pixels;
278 278
279 if (offset <= 0) { 279 if (offset <= 0) {
280 - // Check if listener is same from scrollController.  
281 - // TODO: Improve the way it checks if it the same view controller  
282 - // Use PrimaryScrollController  
283 - if (_scrollController.position.pixels != notification.metrics.pixels &&  
284 - !(_scrollController.position.pixels == 0 &&  
285 - notification.metrics.pixels >= 0)) {  
286 - return;  
287 - }  
288 // Clamping Scroll Physics end with a ScrollEndNotification with a DragEndDetail class 280 // Clamping Scroll Physics end with a ScrollEndNotification with a DragEndDetail class
289 // while Bouncing Scroll Physics or other physics that Overflow don't return a drag end info 281 // while Bouncing Scroll Physics or other physics that Overflow don't return a drag end info
290 282
@@ -297,7 +289,7 @@ class _ModalBottomSheetState extends State<ModalBottomSheet> @@ -297,7 +289,7 @@ class _ModalBottomSheetState extends State<ModalBottomSheet>
297 return; 289 return;
298 } 290 }
299 291
300 -// Otherwise the calculate the velocity with a VelocityTracker 292 + // Otherwise the calculate the velocity with a VelocityTracker
301 if (_velocityTracker == null) { 293 if (_velocityTracker == null) {
302 final pointerKind = defaultPointerDeviceKind(context); 294 final pointerKind = defaultPointerDeviceKind(context);
303 _velocityTracker = VelocityTracker(); 295 _velocityTracker = VelocityTracker();
@@ -331,7 +323,7 @@ class _ModalBottomSheetState extends State<ModalBottomSheet> @@ -331,7 +323,7 @@ class _ModalBottomSheetState extends State<ModalBottomSheet>
331 animationCurve = _defaultCurve; 323 animationCurve = _defaultCurve;
332 _bounceDragController = 324 _bounceDragController =
333 AnimationController(vsync: this, duration: Duration(milliseconds: 300)); 325 AnimationController(vsync: this, duration: Duration(milliseconds: 300));
334 - _scrollController = widget.scrollController ?? ScrollController(); 326 +
335 // Todo: Check if we can remove scroll Controller 327 // Todo: Check if we can remove scroll Controller
336 super.initState(); 328 super.initState();
337 } 329 }
@@ -343,8 +335,7 @@ class _ModalBottomSheetState extends State<ModalBottomSheet> @@ -343,8 +335,7 @@ class _ModalBottomSheetState extends State<ModalBottomSheet>
343 curve: Curves.easeOutSine, 335 curve: Curves.easeOutSine,
344 ); 336 );
345 337
346 - var child = widget.builder(context, _scrollController);  
347 - 338 + var child = widget.child;
348 if (widget.containerBuilder != null) { 339 if (widget.containerBuilder != null) {
349 child = widget.containerBuilder( 340 child = widget.containerBuilder(
350 context, 341 context,
@@ -402,8 +393,10 @@ class _ModalBottomSheetState extends State<ModalBottomSheet> @@ -402,8 +393,10 @@ class _ModalBottomSheetState extends State<ModalBottomSheet>
402 child: RepaintBoundary(child: child), 393 child: RepaintBoundary(child: child),
403 ); 394 );
404 395
405 - return PrimaryScrollStatusBarHandler(  
406 - scrollController: _scrollController, child: child); 396 + return ScrollToTopStatusBarHandler(
  397 + child: child,
  398 + scrollController: _scrollController,
  399 + );
407 } 400 }
408 } 401 }
409 402
@@ -3,6 +3,7 @@ import 'dart:async'; @@ -3,6 +3,7 @@ import 'dart:async';
3 import 'package:flutter/cupertino.dart'; 3 import 'package:flutter/cupertino.dart';
4 import 'package:flutter/foundation.dart'; 4 import 'package:flutter/foundation.dart';
5 import 'package:flutter/material.dart'; 5 import 'package:flutter/material.dart';
  6 +import 'package:modal_bottom_sheet/src/utils/modal_scroll_controller.dart';
6 7
7 import '../modal_bottom_sheet.dart'; 8 import '../modal_bottom_sheet.dart';
8 9
@@ -15,7 +16,6 @@ class _ModalBottomSheet<T> extends StatefulWidget { @@ -15,7 +16,6 @@ class _ModalBottomSheet<T> extends StatefulWidget {
15 this.route, 16 this.route,
16 this.secondAnimationController, 17 this.secondAnimationController,
17 this.bounce = false, 18 this.bounce = false,
18 - this.scrollController,  
19 this.expanded = false, 19 this.expanded = false,
20 this.enableDrag = true, 20 this.enableDrag = true,
21 this.animationCurve, 21 this.animationCurve,
@@ -30,7 +30,6 @@ class _ModalBottomSheet<T> extends StatefulWidget { @@ -30,7 +30,6 @@ class _ModalBottomSheet<T> extends StatefulWidget {
30 final bool enableDrag; 30 final bool enableDrag;
31 final AnimationController secondAnimationController; 31 final AnimationController secondAnimationController;
32 final Curve animationCurve; 32 final Curve animationCurve;
33 - final ScrollController scrollController;  
34 33
35 @override 34 @override
36 _ModalBottomSheetState<T> createState() => _ModalBottomSheetState<T>(); 35 _ModalBottomSheetState<T> createState() => _ModalBottomSheetState<T>();
@@ -56,6 +55,8 @@ class _ModalBottomSheetState<T> extends State<_ModalBottomSheet<T>> { @@ -56,6 +55,8 @@ class _ModalBottomSheetState<T> extends State<_ModalBottomSheet<T>> {
56 return null; 55 return null;
57 } 56 }
58 57
  58 + ScrollController _scrollController;
  59 +
59 @override 60 @override
60 void initState() { 61 void initState() {
61 widget.route.animation.addListener(updateController); 62 widget.route.animation.addListener(updateController);
@@ -65,6 +66,7 @@ class _ModalBottomSheetState<T> extends State<_ModalBottomSheet<T>> { @@ -65,6 +66,7 @@ class _ModalBottomSheetState<T> extends State<_ModalBottomSheet<T>> {
65 @override 66 @override
66 void dispose() { 67 void dispose() {
67 widget.route.animation.removeListener(updateController); 68 widget.route.animation.removeListener(updateController);
  69 + _scrollController?.dispose();
68 super.dispose(); 70 super.dispose();
69 } 71 }
70 72
@@ -75,41 +77,47 @@ class _ModalBottomSheetState<T> extends State<_ModalBottomSheet<T>> { @@ -75,41 +77,47 @@ class _ModalBottomSheetState<T> extends State<_ModalBottomSheet<T>> {
75 @override 77 @override
76 Widget build(BuildContext context) { 78 Widget build(BuildContext context) {
77 assert(debugCheckHasMediaQuery(context)); 79 assert(debugCheckHasMediaQuery(context));
78 -  
79 - return AnimatedBuilder(  
80 - animation: widget.route._animationController,  
81 - builder: (BuildContext context, Widget child) {  
82 - // Disable the initial animation when accessible navigation is on so  
83 - // that the semantics are added to the tree at the correct time.  
84 - return Semantics(  
85 - scopesRoute: true,  
86 - namesRoute: true,  
87 - label: _getRouteLabel(),  
88 - explicitChildNodes: true,  
89 - child: ModalBottomSheet(  
90 - closeProgressThreshold: widget.closeProgressThreshold,  
91 - expanded: widget.route.expanded,  
92 - containerBuilder: widget.route.containerBuilder,  
93 - animationController: widget.route._animationController,  
94 - shouldClose: widget.route._hasScopedWillPopCallback  
95 - ? () async {  
96 - final willPop = await widget.route.willPop();  
97 - return willPop != RoutePopDisposition.doNotPop; 80 + final scrollController = PrimaryScrollController.of(context) ??
  81 + (_scrollController ??= ScrollController());
  82 + return ModalScrollController(
  83 + controller: scrollController,
  84 + child: Builder(
  85 + builder: (context) => AnimatedBuilder(
  86 + animation: widget.route._animationController,
  87 + builder: (BuildContext context, Widget child) {
  88 + // Disable the initial animation when accessible navigation is on so
  89 + // that the semantics are added to the tree at the correct time.
  90 + return Semantics(
  91 + scopesRoute: true,
  92 + namesRoute: true,
  93 + label: _getRouteLabel(),
  94 + explicitChildNodes: true,
  95 + child: ModalBottomSheet(
  96 + expanded: widget.route.expanded,
  97 + containerBuilder: widget.route.containerBuilder,
  98 + animationController: widget.route._animationController,
  99 + shouldClose: widget.route._hasScopedWillPopCallback
  100 + ? () async {
  101 + final willPop = await widget.route.willPop();
  102 + return willPop != RoutePopDisposition.doNotPop;
  103 + }
  104 + : null,
  105 + onClosing: () {
  106 + if (widget.route.isCurrent) {
  107 + Navigator.of(context).pop();
98 } 108 }
99 - : null,  
100 - onClosing: () {  
101 - if (widget.route.isCurrent) {  
102 - Navigator.of(context).pop();  
103 - }  
104 - },  
105 - builder: widget.route.builder,  
106 - enableDrag: widget.enableDrag,  
107 - bounce: widget.bounce,  
108 - scrollController: widget.scrollController,  
109 - animationCurve: widget.animationCurve,  
110 - ),  
111 - );  
112 - }, 109 + },
  110 + child: child,
  111 + enableDrag: widget.enableDrag,
  112 + bounce: widget.bounce,
  113 + scrollController: scrollController,
  114 + animationCurve: widget.animationCurve,
  115 + ),
  116 + );
  117 + },
  118 + child: widget.route.builder(context),
  119 + ),
  120 + ),
113 ); 121 );
114 } 122 }
115 } 123 }
@@ -137,7 +145,7 @@ class ModalBottomSheetRoute<T> extends PopupRoute<T> { @@ -137,7 +145,7 @@ class ModalBottomSheetRoute<T> extends PopupRoute<T> {
137 145
138 final double closeProgressThreshold; 146 final double closeProgressThreshold;
139 final WidgetWithChildBuilder containerBuilder; 147 final WidgetWithChildBuilder containerBuilder;
140 - final ScrollWidgetBuilder builder; 148 + final WidgetBuilder builder;
141 final bool expanded; 149 final bool expanded;
142 final bool bounce; 150 final bool bounce;
143 final Color modalBarrierColor; 151 final Color modalBarrierColor;
@@ -189,7 +197,6 @@ class ModalBottomSheetRoute<T> extends PopupRoute<T> { @@ -189,7 +197,6 @@ class ModalBottomSheetRoute<T> extends PopupRoute<T> {
189 route: this, 197 route: this,
190 secondAnimationController: secondAnimationController, 198 secondAnimationController: secondAnimationController,
191 expanded: expanded, 199 expanded: expanded,
192 - scrollController: scrollController,  
193 bounce: bounce, 200 bounce: bounce,
194 enableDrag: enableDrag, 201 enableDrag: enableDrag,
195 animationCurve: animationCurve, 202 animationCurve: animationCurve,
@@ -218,7 +225,7 @@ class ModalBottomSheetRoute<T> extends PopupRoute<T> { @@ -218,7 +225,7 @@ class ModalBottomSheetRoute<T> extends PopupRoute<T> {
218 /// Shows a modal material design bottom sheet. 225 /// Shows a modal material design bottom sheet.
219 Future<T> showCustomModalBottomSheet<T>({ 226 Future<T> showCustomModalBottomSheet<T>({
220 @required BuildContext context, 227 @required BuildContext context,
221 - @required ScrollWidgetBuilder builder, 228 + @required WidgetBuilder builder,
222 @required WidgetWithChildBuilder containerWidget, 229 @required WidgetWithChildBuilder containerWidget,
223 Color backgroundColor, 230 Color backgroundColor,
224 double elevation, 231 double elevation,
@@ -232,7 +239,6 @@ Future<T> showCustomModalBottomSheet<T>({ @@ -232,7 +239,6 @@ Future<T> showCustomModalBottomSheet<T>({
232 bool useRootNavigator = false, 239 bool useRootNavigator = false,
233 bool isDismissible = true, 240 bool isDismissible = true,
234 bool enableDrag = true, 241 bool enableDrag = true,
235 - ScrollController scrollController,  
236 Duration duration, 242 Duration duration,
237 }) async { 243 }) async {
238 assert(context != null); 244 assert(context != null);
@@ -71,7 +71,7 @@ class BarBottomSheet extends StatelessWidget { @@ -71,7 +71,7 @@ class BarBottomSheet extends StatelessWidget {
71 71
72 Future<T> showBarModalBottomSheet<T>({ 72 Future<T> showBarModalBottomSheet<T>({
73 @required BuildContext context, 73 @required BuildContext context,
74 - @required ScrollWidgetBuilder builder, 74 + @required WidgetBuilder builder,
75 Color backgroundColor, 75 Color backgroundColor,
76 double elevation, 76 double elevation,
77 ShapeBorder shape, 77 ShapeBorder shape,
@@ -67,7 +67,7 @@ class _CupertinoBottomSheetContainer extends StatelessWidget { @@ -67,7 +67,7 @@ class _CupertinoBottomSheetContainer extends StatelessWidget {
67 67
68 Future<T> showCupertinoModalBottomSheet<T>({ 68 Future<T> showCupertinoModalBottomSheet<T>({
69 @required BuildContext context, 69 @required BuildContext context,
70 - @required ScrollWidgetBuilder builder, 70 + @required WidgetBuilder builder,
71 Color backgroundColor, 71 Color backgroundColor,
72 double elevation, 72 double elevation,
73 double closeProgressThreshold, 73 double closeProgressThreshold,
@@ -139,7 +139,7 @@ class CupertinoModalBottomSheetRoute<T> extends ModalBottomSheetRoute<T> { @@ -139,7 +139,7 @@ class CupertinoModalBottomSheetRoute<T> extends ModalBottomSheetRoute<T> {
139 final Color transitionBackgroundColor; 139 final Color transitionBackgroundColor;
140 140
141 CupertinoModalBottomSheetRoute({ 141 CupertinoModalBottomSheetRoute({
142 - ScrollWidgetBuilder builder, 142 + WidgetBuilder builder,
143 WidgetWithChildBuilder containerBuilder, 143 WidgetWithChildBuilder containerBuilder,
144 double closeProgressThreshold, 144 double closeProgressThreshold,
145 String barrierLabel, 145 String barrierLabel,
@@ -321,8 +321,8 @@ class CupertinoScaffold extends StatefulWidget { @@ -321,8 +321,8 @@ class CupertinoScaffold extends StatefulWidget {
321 321
322 static Future<T> showCupertinoModalBottomSheet<T>({ 322 static Future<T> showCupertinoModalBottomSheet<T>({
323 @required BuildContext context, 323 @required BuildContext context,
324 - @required ScrollWidgetBuilder builder,  
325 double closeProgressThreshold, 324 double closeProgressThreshold,
  325 + @required WidgetBuilder builder,
326 Curve animationCurve, 326 Curve animationCurve,
327 Curve previousRouteAnimationCurve, 327 Curve previousRouteAnimationCurve,
328 Color backgroundColor, 328 Color backgroundColor,
@@ -5,8 +5,8 @@ import 'dart:async'; @@ -5,8 +5,8 @@ import 'dart:async';
5 /// Shows a modal material design bottom sheet. 5 /// Shows a modal material design bottom sheet.
6 Future<T> showMaterialModalBottomSheet<T>({ 6 Future<T> showMaterialModalBottomSheet<T>({
7 @required BuildContext context, 7 @required BuildContext context,
8 - @required ScrollWidgetBuilder builder,  
9 double closeProgressThreshold, 8 double closeProgressThreshold,
  9 + @required WidgetBuilder builder,
10 Color backgroundColor, 10 Color backgroundColor,
11 double elevation, 11 double elevation,
12 ShapeBorder shape, 12 ShapeBorder shape,
  1 +import 'package:flutter/rendering.dart';
  2 +import 'package:flutter/widgets.dart';
  3 +
  4 +/// Associates a [ScrollController] with a subtree.
  5 +///
  6 +/// This mechanism can be used to provide default behavior for scroll views in a
  7 +/// subtree inside a modal bottom sheet.
  8 +///
  9 +/// We want to remove this and use [PrimaryScrollController].
  10 +/// This issue should be solved first https://github.com/flutter/flutter/issues/64236
  11 +///
  12 +/// See [PrimaryScrollController]
  13 +class ModalScrollController extends InheritedWidget {
  14 + /// Creates a widget that associates a [ScrollController] with a subtree.
  15 + ModalScrollController({
  16 + Key key,
  17 + @required this.controller,
  18 + @required Widget child,
  19 + }) : assert(controller != null),
  20 + super(
  21 + key: key,
  22 + child: PrimaryScrollController(
  23 + controller: controller,
  24 + child: child,
  25 + ),
  26 + );
  27 +
  28 + /// The [ScrollController] associated with the subtree.
  29 + ///
  30 + /// See also:
  31 + ///
  32 + /// * [ScrollView.controller], which discusses the purpose of specifying a
  33 + /// scroll controller.
  34 + final ScrollController controller;
  35 +
  36 + /// Returns the [ScrollController] most closely associated with the given
  37 + /// context.
  38 + ///
  39 + /// Returns null if there is no [ScrollController] associated with the given
  40 + /// context.
  41 + static ScrollController of(BuildContext context) {
  42 + final ModalScrollController result =
  43 + context.dependOnInheritedWidgetOfExactType<ModalScrollController>();
  44 + return result?.controller;
  45 + }
  46 +
  47 + @override
  48 + bool updateShouldNotify(ModalScrollController oldWidget) =>
  49 + controller != oldWidget.controller;
  50 +
  51 + @override
  52 + void debugFillProperties(DiagnosticPropertiesBuilder properties) {
  53 + super.debugFillProperties(properties);
  54 + properties.add(DiagnosticsProperty<ScrollController>(
  55 + 'controller', controller,
  56 + ifNull: 'no controller', showName: false));
  57 + }
  58 +}
1 import 'package:flutter/widgets.dart'; 1 import 'package:flutter/widgets.dart';
2 2
3 -/// Creates a primary scroll controller that will  
4 -/// scroll to the top when tapped on the status bar 3 +/// Widget that that will scroll to the top the ScrollController
  4 +/// when tapped on the status bar
5 /// 5 ///
6 -class PrimaryScrollStatusBarHandler extends StatefulWidget {  
7 - final ScrollController scrollController; 6 +class ScrollToTopStatusBarHandler extends StatefulWidget {
8 final Widget child; 7 final Widget child;
  8 + final ScrollController scrollController;
  9 +
  10 + const ScrollToTopStatusBarHandler({
  11 + Key key,
  12 + @required this.child,
  13 + @required this.scrollController,
  14 + }) : super(key: key);
9 15
10 - const PrimaryScrollStatusBarHandler(  
11 - {Key key, this.child, this.scrollController})  
12 - : super(key: key);  
13 @override 16 @override
14 - _PrimaryScrollWidgetState createState() => _PrimaryScrollWidgetState(); 17 + _ScrollToTopStatusBarState createState() => _ScrollToTopStatusBarState();
15 } 18 }
16 19
17 -class _PrimaryScrollWidgetState extends State<PrimaryScrollStatusBarHandler> {  
18 - ScrollController controller;  
19 - 20 +class _ScrollToTopStatusBarState extends State<ScrollToTopStatusBarHandler> {
20 @override 21 @override
21 void initState() { 22 void initState() {
22 - controller = widget.scrollController ?? ScrollController();  
23 super.initState(); 23 super.initState();
24 } 24 }
25 25
26 @override 26 @override
27 Widget build(BuildContext context) { 27 Widget build(BuildContext context) {
28 - return PrimaryScrollController(  
29 - controller: controller,  
30 - child: Stack(  
31 - fit: StackFit.expand,  
32 - children: [  
33 - widget.child,  
34 - Positioned(  
35 - top: 0,  
36 - left: 0,  
37 - right: 0,  
38 - height: MediaQuery.of(context).padding.top,  
39 - child: Builder(  
40 - builder: (context) => GestureDetector(  
41 - behavior: HitTestBehavior.opaque,  
42 - onTap: () => _handleStatusBarTap(context),  
43 - // iOS accessibility automatically adds scroll-to-top to the clock in the status bar  
44 - excludeFromSemantics: true,  
45 - ), 28 + return Stack(
  29 + fit: StackFit.expand,
  30 + children: [
  31 + widget.child,
  32 + Positioned(
  33 + top: 0,
  34 + left: 0,
  35 + right: 0,
  36 + height: MediaQuery.of(context).padding.top,
  37 + child: Builder(
  38 + builder: (context) => GestureDetector(
  39 + behavior: HitTestBehavior.opaque,
  40 + onTap: () => _handleStatusBarTap(context),
  41 + // iOS accessibility automatically adds scroll-to-top to the clock in the status bar
  42 + excludeFromSemantics: true,
46 ), 43 ),
47 ), 44 ),
48 - ],  
49 - ), 45 + ),
  46 + ],
50 ); 47 );
51 } 48 }
52 49
53 void _handleStatusBarTap(BuildContext context) { 50 void _handleStatusBarTap(BuildContext context) {
54 - final controller = PrimaryScrollController.of(context);  
55 - if (controller.hasClients) { 51 + final controller = widget.scrollController;
  52 + if (controller != null && controller.hasClients) {
56 controller.animateTo( 53 controller.animateTo(
57 0.0, 54 0.0,
58 duration: const Duration(milliseconds: 300), 55 duration: const Duration(milliseconds: 300),