Jaime Blasco
Committed by GitHub

Merge pull request #36 from jamesblasco/nested_scroll

Nested scroll
@@ -11,6 +11,7 @@ import 'modals/modal_fit.dart'; @@ -11,6 +11,7 @@ import 'modals/modal_fit.dart';
11 import 'modals/modal_inside_modal.dart'; 11 import 'modals/modal_inside_modal.dart';
12 import 'modals/modal_will_scope.dart'; 12 import 'modals/modal_will_scope.dart';
13 import 'modals/modal_with_navigator.dart'; 13 import 'modals/modal_with_navigator.dart';
  14 +import 'modals/modal_with_nested_scroll.dart';
14 import 'modals/modal_with_scroll.dart'; 15 import 'modals/modal_with_scroll.dart';
15 16
16 import 'examples/cupertino_share.dart'; 17 import 'examples/cupertino_share.dart';
@@ -219,7 +220,7 @@ class _MyHomePageState extends State<MyHomePage> { @@ -219,7 +220,7 @@ class _MyHomePageState extends State<MyHomePage> {
219 scrollController: scrollController), 220 scrollController: scrollController),
220 )), 221 )),
221 ListTile( 222 ListTile(
222 - title: Text('Cupertino Modal with WillPopScope'), 223 + title: Text('Modal with WillPopScope'),
223 onTap: () => showCupertinoModalBottomSheet( 224 onTap: () => showCupertinoModalBottomSheet(
224 expand: true, 225 expand: true,
225 context: context, 226 context: context,
@@ -228,6 +229,15 @@ class _MyHomePageState extends State<MyHomePage> { @@ -228,6 +229,15 @@ class _MyHomePageState extends State<MyHomePage> {
228 ModalWillScope( 229 ModalWillScope(
229 scrollController: scrollController), 230 scrollController: scrollController),
230 )), 231 )),
  232 + ListTile(
  233 + title: Text('Modal with Nested Scroll'),
  234 + onTap: () => showCupertinoModalBottomSheet(
  235 + expand: true,
  236 + context: context,
  237 + builder: (context, scrollController) =>
  238 + NestedScrollModal(
  239 + scrollController: scrollController),
  240 + )),
231 ], 241 ],
232 ), 242 ),
233 ), 243 ),
  1 +import 'package:flutter/cupertino.dart';
  2 +import 'package:flutter/material.dart';
  3 +
  4 +class NestedScrollModal extends StatelessWidget {
  5 + final ScrollController scrollController;
  6 +
  7 + const NestedScrollModal({Key key, this.scrollController}) : super(key: key);
  8 +
  9 + @override
  10 + Widget build(BuildContext context) {
  11 + return NestedScrollView(
  12 +
  13 + physics: ScrollPhysics(parent: PageScrollPhysics()),
  14 + headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
  15 + return <Widget>[
  16 + SliverList(
  17 + delegate: SliverChildListDelegate(
  18 + [
  19 + Container(height: 300, color: Colors.blue),
  20 + ],
  21 + ),
  22 + ),
  23 + ];
  24 + },
  25 + body: ListView.builder(
  26 + controller: scrollController,
  27 + itemBuilder: (context, index) {
  28 + return Container(
  29 + height: 100,
  30 + color: index.isOdd ? Colors.green : Colors.orange,
  31 + );
  32 + },
  33 + itemCount: 12,
  34 + ));
  35 + }
  36 +}
@@ -244,17 +244,19 @@ class _ModalBottomSheetState extends State<ModalBottomSheet> @@ -244,17 +244,19 @@ class _ModalBottomSheetState extends State<ModalBottomSheet>
244 DateTime _startTime; 244 DateTime _startTime;
245 245
246 void _handleScrollUpdate(ScrollNotification notification) { 246 void _handleScrollUpdate(ScrollNotification notification) {
247 -  
248 final scrollPosition = _scrollController.position; 247 final scrollPosition = _scrollController.position;
249 248
  249 + if (scrollPosition.axis == Axis.horizontal) return;
  250 +
  251 + //Check if scrollController is used
  252 + if (!_scrollController.hasClients) return;
  253 +
250 final isScrollReversed = scrollPosition.axisDirection == AxisDirection.down; 254 final isScrollReversed = scrollPosition.axisDirection == AxisDirection.down;
251 final offset = isScrollReversed 255 final offset = isScrollReversed
252 ? scrollPosition.pixels 256 ? scrollPosition.pixels
253 : scrollPosition.maxScrollExtent - scrollPosition.pixels; 257 : scrollPosition.maxScrollExtent - scrollPosition.pixels;
254 258
255 if (offset <= 0) { 259 if (offset <= 0) {
256 - //Check if scrollController is used  
257 - if (!_scrollController.hasClients) return;  
258 // Check if listener is same from scrollController. 260 // Check if listener is same from scrollController.
259 // TODO: Improve the way it checks if it the same view controller 261 // TODO: Improve the way it checks if it the same view controller
260 // Use PrimaryScrollController 262 // Use PrimaryScrollController
@@ -274,9 +276,9 @@ class _ModalBottomSheetState extends State<ModalBottomSheet> @@ -274,9 +276,9 @@ class _ModalBottomSheetState extends State<ModalBottomSheet>
274 _startTime = null; 276 _startTime = null;
275 return; 277 return;
276 } 278 }
277 - 279 +
278 // Otherwise the calculate the velocity with a VelocityTracker 280 // Otherwise the calculate the velocity with a VelocityTracker
279 - if (_velocityTracker == null) { 281 + if (_velocityTracker == null) {
280 _velocityTracker = VelocityTracker(); 282 _velocityTracker = VelocityTracker();
281 _startTime = DateTime.now(); 283 _startTime = DateTime.now();
282 } 284 }
@@ -84,6 +84,7 @@ Future<T> showCupertinoModalBottomSheet<T>({ @@ -84,6 +84,7 @@ Future<T> showCupertinoModalBottomSheet<T>({
84 Radius topRadius = _default_top_radius, 84 Radius topRadius = _default_top_radius,
85 Duration duration, 85 Duration duration,
86 RouteSettings settings, 86 RouteSettings settings,
  87 + Color transitionBackgroundColor,
87 }) async { 88 }) async {
88 assert(context != null); 89 assert(context != null);
89 assert(builder != null); 90 assert(builder != null);
@@ -121,6 +122,7 @@ Future<T> showCupertinoModalBottomSheet<T>({ @@ -121,6 +122,7 @@ Future<T> showCupertinoModalBottomSheet<T>({
121 previousRouteAnimationCurve: previousRouteAnimationCurve, 122 previousRouteAnimationCurve: previousRouteAnimationCurve,
122 duration: duration, 123 duration: duration,
123 settings: settings, 124 settings: settings,
  125 + transitionBackgroundColor: transitionBackgroundColor ?? Colors.black
124 )); 126 ));
125 return result; 127 return result;
126 } 128 }
@@ -129,6 +131,10 @@ class CupertinoModalBottomSheetRoute<T> extends ModalBottomSheetRoute<T> { @@ -129,6 +131,10 @@ class CupertinoModalBottomSheetRoute<T> extends ModalBottomSheetRoute<T> {
129 final Radius topRadius; 131 final Radius topRadius;
130 final Curve previousRouteAnimationCurve; 132 final Curve previousRouteAnimationCurve;
131 133
  134 + // Background color behind all routes
  135 + // Black by default
  136 + final Color transitionBackgroundColor;
  137 +
132 CupertinoModalBottomSheetRoute({ 138 CupertinoModalBottomSheetRoute({
133 ScrollWidgetBuilder builder, 139 ScrollWidgetBuilder builder,
134 WidgetWithChildBuilder containerBuilder, 140 WidgetWithChildBuilder containerBuilder,
@@ -145,6 +151,7 @@ class CupertinoModalBottomSheetRoute<T> extends ModalBottomSheetRoute<T> { @@ -145,6 +151,7 @@ class CupertinoModalBottomSheetRoute<T> extends ModalBottomSheetRoute<T> {
145 @required bool expanded, 151 @required bool expanded,
146 Duration duration, 152 Duration duration,
147 RouteSettings settings, 153 RouteSettings settings,
  154 + this.transitionBackgroundColor,
148 this.topRadius = _default_top_radius, 155 this.topRadius = _default_top_radius,
149 this.previousRouteAnimationCurve, 156 this.previousRouteAnimationCurve,
150 }) : assert(expanded != null), 157 }) : assert(expanded != null),
@@ -199,6 +206,7 @@ class CupertinoModalBottomSheetRoute<T> extends ModalBottomSheetRoute<T> { @@ -199,6 +206,7 @@ class CupertinoModalBottomSheetRoute<T> extends ModalBottomSheetRoute<T> {
199 body: child, 206 body: child,
200 animationCurve: previousRouteAnimationCurve, 207 animationCurve: previousRouteAnimationCurve,
201 topRadius: topRadius, 208 topRadius: topRadius,
  209 + backgroundColor: transitionBackgroundColor ?? Colors.black,
202 ); 210 );
203 } 211 }
204 } 212 }
@@ -207,6 +215,7 @@ class _CupertinoModalTransition extends StatelessWidget { @@ -207,6 +215,7 @@ class _CupertinoModalTransition extends StatelessWidget {
207 final Animation<double> secondaryAnimation; 215 final Animation<double> secondaryAnimation;
208 final Radius topRadius; 216 final Radius topRadius;
209 final Curve animationCurve; 217 final Curve animationCurve;
  218 + final Color backgroundColor;
210 219
211 final Widget body; 220 final Widget body;
212 221
@@ -215,6 +224,7 @@ class _CupertinoModalTransition extends StatelessWidget { @@ -215,6 +224,7 @@ class _CupertinoModalTransition extends StatelessWidget {
215 @required this.secondaryAnimation, 224 @required this.secondaryAnimation,
216 @required this.body, 225 @required this.body,
217 @required this.topRadius, 226 @required this.topRadius,
  227 + this.backgroundColor = Colors.black,
218 this.animationCurve, 228 this.animationCurve,
219 }) : super(key: key); 229 }) : super(key: key);
220 230
@@ -246,7 +256,7 @@ class _CupertinoModalTransition extends StatelessWidget { @@ -246,7 +256,7 @@ class _CupertinoModalTransition extends StatelessWidget {
246 : (1 - progress) * startRoundCorner + progress * topRadius.x; 256 : (1 - progress) * startRoundCorner + progress * topRadius.x;
247 return Stack( 257 return Stack(
248 children: <Widget>[ 258 children: <Widget>[
249 - Container(color: Colors.black), 259 + Container(color: backgroundColor),
250 Transform.translate( 260 Transform.translate(
251 offset: Offset(0, yOffset), 261 offset: Offset(0, yOffset),
252 child: Transform.scale( 262 child: Transform.scale(
@@ -266,6 +276,7 @@ class _CupertinoModalTransition extends StatelessWidget { @@ -266,6 +276,7 @@ class _CupertinoModalTransition extends StatelessWidget {
266 276
267 class _CupertinoScaffold extends InheritedWidget { 277 class _CupertinoScaffold extends InheritedWidget {
268 final AnimationController animation; 278 final AnimationController animation;
  279 +
269 final Radius topRadius; 280 final Radius topRadius;
270 281
271 @override 282 @override
@@ -288,10 +299,14 @@ class CupertinoScaffold extends StatefulWidget { @@ -288,10 +299,14 @@ class CupertinoScaffold extends StatefulWidget {
288 299
289 final Widget body; 300 final Widget body;
290 final Radius topRadius; 301 final Radius topRadius;
  302 + final Color transitionBackgroundColor;
291 303
292 - const CupertinoScaffold(  
293 - {Key key, this.body, this.topRadius = _default_top_radius})  
294 - : super(key: key); 304 + const CupertinoScaffold({
  305 + Key key,
  306 + this.body,
  307 + this.topRadius = _default_top_radius,
  308 + this.transitionBackgroundColor = Colors.black,
  309 + }) : super(key: key);
295 310
296 @override 311 @override
297 State<StatefulWidget> createState() => _CupertinoScaffoldState(); 312 State<StatefulWidget> createState() => _CupertinoScaffoldState();
@@ -376,6 +391,7 @@ class _CupertinoScaffoldState extends State<CupertinoScaffold> @@ -376,6 +391,7 @@ class _CupertinoScaffoldState extends State<CupertinoScaffold>
376 secondaryAnimation: animationController, 391 secondaryAnimation: animationController,
377 body: widget.body, 392 body: widget.body,
378 topRadius: widget.topRadius, 393 topRadius: widget.topRadius,
  394 + backgroundColor: widget.transitionBackgroundColor,
379 ), 395 ),
380 ); 396 );
381 } 397 }
1 # Generated by pub 1 # Generated by pub
2 # See https://dart.dev/tools/pub/glossary#lockfile 2 # See https://dart.dev/tools/pub/glossary#lockfile
3 packages: 3 packages:
4 - archive:  
5 - dependency: transitive  
6 - description:  
7 - name: archive  
8 - url: "https://pub.dartlang.org"  
9 - source: hosted  
10 - version: "2.0.13"  
11 - args:  
12 - dependency: transitive  
13 - description:  
14 - name: args  
15 - url: "https://pub.dartlang.org"  
16 - source: hosted  
17 - version: "1.6.0"  
18 async: 4 async:
19 dependency: transitive 5 dependency: transitive
20 description: 6 description:
@@ -29,6 +15,13 @@ packages: @@ -29,6 +15,13 @@ packages:
29 url: "https://pub.dartlang.org" 15 url: "https://pub.dartlang.org"
30 source: hosted 16 source: hosted
31 version: "2.0.0" 17 version: "2.0.0"
  18 + characters:
  19 + dependency: transitive
  20 + description:
  21 + name: characters
  22 + url: "https://pub.dartlang.org"
  23 + source: hosted
  24 + version: "1.0.0"
32 charcode: 25 charcode:
33 dependency: transitive 26 dependency: transitive
34 description: 27 description:
@@ -36,27 +29,27 @@ packages: @@ -36,27 +29,27 @@ packages:
36 url: "https://pub.dartlang.org" 29 url: "https://pub.dartlang.org"
37 source: hosted 30 source: hosted
38 version: "1.1.3" 31 version: "1.1.3"
39 - collection: 32 + clock:
40 dependency: transitive 33 dependency: transitive
41 description: 34 description:
42 - name: collection 35 + name: clock
43 url: "https://pub.dartlang.org" 36 url: "https://pub.dartlang.org"
44 source: hosted 37 source: hosted
45 - version: "1.14.12"  
46 - convert: 38 + version: "1.0.1"
  39 + collection:
47 dependency: transitive 40 dependency: transitive
48 description: 41 description:
49 - name: convert 42 + name: collection
50 url: "https://pub.dartlang.org" 43 url: "https://pub.dartlang.org"
51 source: hosted 44 source: hosted
52 - version: "2.1.1"  
53 - crypto: 45 + version: "1.14.13"
  46 + fake_async:
54 dependency: transitive 47 dependency: transitive
55 description: 48 description:
56 - name: crypto 49 + name: fake_async
57 url: "https://pub.dartlang.org" 50 url: "https://pub.dartlang.org"
58 source: hosted 51 source: hosted
59 - version: "2.1.4" 52 + version: "1.1.0"
60 flutter: 53 flutter:
61 dependency: "direct main" 54 dependency: "direct main"
62 description: flutter 55 description: flutter
@@ -67,20 +60,13 @@ packages: @@ -67,20 +60,13 @@ packages:
67 description: flutter 60 description: flutter
68 source: sdk 61 source: sdk
69 version: "0.0.0" 62 version: "0.0.0"
70 - image:  
71 - dependency: transitive  
72 - description:  
73 - name: image  
74 - url: "https://pub.dartlang.org"  
75 - source: hosted  
76 - version: "2.1.12"  
77 matcher: 63 matcher:
78 dependency: transitive 64 dependency: transitive
79 description: 65 description:
80 name: matcher 66 name: matcher
81 url: "https://pub.dartlang.org" 67 url: "https://pub.dartlang.org"
82 source: hosted 68 source: hosted
83 - version: "0.12.6" 69 + version: "0.12.8"
84 meta: 70 meta:
85 dependency: transitive 71 dependency: transitive
86 description: 72 description:
@@ -94,28 +80,14 @@ packages: @@ -94,28 +80,14 @@ packages:
94 name: path 80 name: path
95 url: "https://pub.dartlang.org" 81 url: "https://pub.dartlang.org"
96 source: hosted 82 source: hosted
97 - version: "1.6.4" 83 + version: "1.7.0"
98 pedantic: 84 pedantic:
99 dependency: "direct dev" 85 dependency: "direct dev"
100 description: 86 description:
101 name: pedantic 87 name: pedantic
102 url: "https://pub.dartlang.org" 88 url: "https://pub.dartlang.org"
103 source: hosted 89 source: hosted
104 - version: "1.8.0+1"  
105 - petitparser:  
106 - dependency: transitive  
107 - description:  
108 - name: petitparser  
109 - url: "https://pub.dartlang.org"  
110 - source: hosted  
111 - version: "2.4.0"  
112 - quiver:  
113 - dependency: transitive  
114 - description:  
115 - name: quiver  
116 - url: "https://pub.dartlang.org"  
117 - source: hosted  
118 - version: "2.1.3" 90 + version: "1.9.0"
119 sky_engine: 91 sky_engine:
120 dependency: transitive 92 dependency: transitive
121 description: flutter 93 description: flutter
@@ -162,7 +134,7 @@ packages: @@ -162,7 +134,7 @@ packages:
162 name: test_api 134 name: test_api
163 url: "https://pub.dartlang.org" 135 url: "https://pub.dartlang.org"
164 source: hosted 136 source: hosted
165 - version: "0.2.15" 137 + version: "0.2.17"
166 typed_data: 138 typed_data:
167 dependency: transitive 139 dependency: transitive
168 description: 140 description:
@@ -177,13 +149,6 @@ packages: @@ -177,13 +149,6 @@ packages:
177 url: "https://pub.dartlang.org" 149 url: "https://pub.dartlang.org"
178 source: hosted 150 source: hosted
179 version: "2.0.8" 151 version: "2.0.8"
180 - xml:  
181 - dependency: transitive  
182 - description:  
183 - name: xml  
184 - url: "https://pub.dartlang.org"  
185 - source: hosted  
186 - version: "3.6.1"  
187 sdks: 152 sdks:
188 - dart: ">=2.6.0 <3.0.0" 153 + dart: ">=2.9.0-14.0.dev <3.0.0"
189 flutter: ">=1.12.0 <2.0.0" 154 flutter: ">=1.12.0 <2.0.0"