Jaime Blasco

Add support to close by dragging fast on a modal with a scroll view.

ScrollNotification doesn't allow you to get the DragDownDetails of the drag gesture of the scroll view.

I used VelocityTracker to calculate the velocity when the drag of the scroll ends
@@ -213,13 +213,11 @@ class _ModalBottomSheetState extends State<ModalBottomSheet> @@ -213,13 +213,11 @@ class _ModalBottomSheetState extends State<ModalBottomSheet>
213 // If speed is bigger than _minFlingVelocity try to close it 213 // If speed is bigger than _minFlingVelocity try to close it
214 if (velocity > _minFlingVelocity) { 214 if (velocity > _minFlingVelocity) {
215 _close(); 215 _close();
216 - print('close2');  
217 } else if (hasReachedCloseThreshold) { 216 } else if (hasReachedCloseThreshold) {
218 if (widget.animationController.value > 0.0) { 217 if (widget.animationController.value > 0.0) {
219 widget.animationController.fling(velocity: -1.0); 218 widget.animationController.fling(velocity: -1.0);
220 } 219 }
221 _close(); 220 _close();
222 - print('close3');  
223 } else { 221 } else {
224 _cancelClose(); 222 _cancelClose();
225 } 223 }
@@ -228,6 +226,14 @@ class _ModalBottomSheetState extends State<ModalBottomSheet> @@ -228,6 +226,14 @@ class _ModalBottomSheetState extends State<ModalBottomSheet>
228 } 226 }
229 } 227 }
230 228
  229 +
  230 + // As we cannot access the dragGesture detector of the scroll view
  231 + // we can not know the DragDownDetails and therefore the end velocity.
  232 + // VelocityTracker it is used to calculate the end velocity of the scroll
  233 + // when user is trying to close the modal by dragging
  234 + VelocityTracker _velocityTracker;
  235 + DateTime _startTime;
  236 +
231 void _handleScrollUpdate(ScrollNotification notification) { 237 void _handleScrollUpdate(ScrollNotification notification) {
232 if (notification.metrics.pixels <= notification.metrics.minScrollExtent) { 238 if (notification.metrics.pixels <= notification.metrics.minScrollExtent) {
233 //Check if listener is same from scrollController 239 //Check if listener is same from scrollController
@@ -235,6 +241,10 @@ class _ModalBottomSheetState extends State<ModalBottomSheet> @@ -235,6 +241,10 @@ class _ModalBottomSheetState extends State<ModalBottomSheet>
235 return; 241 return;
236 } 242 }
237 DragUpdateDetails dragDetails; 243 DragUpdateDetails dragDetails;
  244 + if (notification is ScrollStartNotification) {
  245 + _velocityTracker = VelocityTracker();
  246 + _startTime = DateTime.now();
  247 + }
238 if (notification is ScrollUpdateNotification) { 248 if (notification is ScrollUpdateNotification) {
239 dragDetails = notification.dragDetails; 249 dragDetails = notification.dragDetails;
240 } 250 }
@@ -242,12 +252,16 @@ class _ModalBottomSheetState extends State<ModalBottomSheet> @@ -242,12 +252,16 @@ class _ModalBottomSheetState extends State<ModalBottomSheet>
242 dragDetails = notification.dragDetails; 252 dragDetails = notification.dragDetails;
243 } 253 }
244 if (dragDetails != null) { 254 if (dragDetails != null) {
245 - print('scroll'); 255 + final duration = _startTime.difference(DateTime.now());
  256 + print(duration);
  257 + final offset = Offset(0, _scrollController.offset);
  258 + _velocityTracker.addPosition(duration, offset);
246 _handleDragUpdate(dragDetails.primaryDelta); 259 _handleDragUpdate(dragDetails.primaryDelta);
247 } 260 }
248 - // Todo: detect dragEnd during scroll so it can bottom sheet can close  
249 - // if velocity > _minFlingVelocity  
250 - else if (isDragging) _handleDragEnd(0); 261 + else if (isDragging) {
  262 + final velocity = _velocityTracker.getVelocity().pixelsPerSecond.dy;
  263 + _handleDragEnd(velocity);
  264 + }
251 } 265 }
252 } 266 }
253 267