@@ -86,8 +86,8 @@ class DraggableScrollableController extends ChangeNotifier {
86
86
return _attachedController! .extent.pixelsToSize (pixels);
87
87
}
88
88
89
- /// Animates the attached sheet from its current size to [size] to the
90
- /// provided new `size` , a fractional value of the parent container's height.
89
+ /// Animates the attached sheet from its current size to the given [size] , a
90
+ /// fractional value of the parent container's height.
91
91
///
92
92
/// Any active sheet animation is canceled. If the sheet's internal scrollable
93
93
/// is currently animating (e.g. responding to a user fling), that animation is
@@ -101,6 +101,9 @@ class DraggableScrollableController extends ChangeNotifier {
101
101
/// The duration must not be zero. To jump to a particular value without an
102
102
/// animation, use [jumpTo] .
103
103
///
104
+ /// The sheet will not snap after calling [animateTo] even if [DraggableScrollableSheet.snap]
105
+ /// is true. Snapping only occurs after user drags.
106
+ ///
104
107
/// When calling [animateTo] in widget tests, `await` ing the returned
105
108
/// [Future] may cause the test to hang and timeout. Instead, use
106
109
/// [WidgetTester.pumpAndSettle] .
@@ -120,6 +123,7 @@ class DraggableScrollableController extends ChangeNotifier {
120
123
_attachedController! .position.goIdle ();
121
124
// This disables any snapping until the next user interaction with the sheet.
122
125
_attachedController! .extent.hasDragged = false ;
126
+ _attachedController! .extent.hasChanged = true ;
123
127
_attachedController! .extent.startActivity (onCanceled: () {
124
128
// Don't stop the controller if it's already finished and may have been disposed.
125
129
if (animationController.isAnimating) {
@@ -149,13 +153,17 @@ class DraggableScrollableController extends ChangeNotifier {
149
153
/// Any active sheet animation is canceled. If the sheet's inner scrollable
150
154
/// is currently animating (e.g. responding to a user fling), that animation is
151
155
/// canceled as well.
156
+ ///
157
+ /// The sheet will not snap after calling [jumpTo] even if [DraggableScrollableSheet.snap]
158
+ /// is true. Snapping only occurs after user drags.
152
159
void jumpTo (double size) {
153
160
_assertAttached ();
154
161
assert (size >= 0 && size <= 1 );
155
162
// Call start activity to interrupt any other playing activities.
156
163
_attachedController! .extent.startActivity (onCanceled: () {});
157
164
_attachedController! .position.goIdle ();
158
165
_attachedController! .extent.hasDragged = false ;
166
+ _attachedController! .extent.hasChanged = true ;
159
167
_attachedController! .extent.updateSize (size, _attachedController! .position.context.notificationContext! );
160
168
}
161
169
@@ -231,6 +239,10 @@ class DraggableScrollableController extends ChangeNotifier {
231
239
/// [minChildSize] and [maxChildSize] . Use [snapSizes] to add more sizes for
232
240
/// the sheet to snap between.
233
241
///
242
+ /// The snapping effect is only applied on user drags. Programmatically
243
+ /// manipulating the sheet size via [DraggableScrollableController.animateTo] or
244
+ /// [DraggableScrollableController.jumpTo] will ignore [snap] and [snapSizes] .
245
+ ///
234
246
/// By default, the widget will expand its non-occupied area to fill available
235
247
/// space in the parent. If this is not desired, e.g. because the parent wants
236
248
/// to position sheet based on the space it is taking, the [expand] property
@@ -342,6 +354,9 @@ class DraggableScrollableSheet extends StatefulWidget {
342
354
/// snap to the next snap size (see [snapSizes] ) in the direction of the drag.
343
355
/// If their finger was still, the widget will snap to the nearest snap size.
344
356
///
357
+ /// Snapping is not applied when the sheet is programmatically moved by
358
+ /// calling [DraggableScrollableController.animateTo] or [DraggableScrollableController.jumpTo] .
359
+ ///
345
360
/// Rebuilding the sheet with snap newly enabled will immediately trigger a
346
361
/// snap unless the sheet has not yet been dragged away from
347
362
/// [initialChildSize] since first being built or since the last call to
@@ -477,6 +492,7 @@ class _DraggableSheetExtent {
477
492
this .snapAnimationDuration,
478
493
ValueNotifier <double >? currentSize,
479
494
bool ? hasDragged,
495
+ bool ? hasChanged,
480
496
}) : assert (minSize != null ),
481
497
assert (maxSize != null ),
482
498
assert (initialSize != null ),
@@ -487,7 +503,8 @@ class _DraggableSheetExtent {
487
503
_currentSize = (currentSize ?? ValueNotifier <double >(initialSize))
488
504
..addListener (onSizeChanged),
489
505
availablePixels = double .infinity,
490
- hasDragged = hasDragged ?? false ;
506
+ hasDragged = hasDragged ?? false ,
507
+ hasChanged = hasChanged ?? false ;
491
508
492
509
VoidCallback ? _cancelActivity;
493
510
@@ -501,10 +518,20 @@ class _DraggableSheetExtent {
501
518
final VoidCallback onSizeChanged;
502
519
double availablePixels;
503
520
504
- // Used to disable snapping until the user has dragged on the sheet. We do
505
- // this because we don't want to snap away from an initial or programmatically set size.
521
+ // Used to disable snapping until the user has dragged on the sheet.
506
522
bool hasDragged;
507
523
524
+ // Used to determine if the sheet should move to a new initial size when it
525
+ // changes.
526
+ // We need both `hasChanged` and `hasDragged` to achieve the following
527
+ // behavior:
528
+ // 1. The sheet should only snap following user drags (as opposed to
529
+ // programmatic sheet changes). See docs for `animateTo` and `jumpTo`.
530
+ // 2. The sheet should move to a new initial child size on rebuild iff the
531
+ // sheet has not changed, either by drag or programmatic control. See
532
+ // docs for `initialChildSize`.
533
+ bool hasChanged;
534
+
508
535
bool get isAtMin => minSize >= _currentSize.value;
509
536
bool get isAtMax => maxSize <= _currentSize.value;
510
537
@@ -538,6 +565,7 @@ class _DraggableSheetExtent {
538
565
// The user has interacted with the sheet, set `hasDragged` to true so that
539
566
// we'll snap if applicable.
540
567
hasDragged = true ;
568
+ hasChanged = true ;
541
569
if (availablePixels == 0 ) {
542
570
return ;
543
571
}
@@ -590,11 +618,13 @@ class _DraggableSheetExtent {
590
618
snapAnimationDuration: snapAnimationDuration,
591
619
initialSize: initialSize,
592
620
onSizeChanged: onSizeChanged,
593
- // Use the possibly updated initialSize if the user hasn't dragged yet.
594
- currentSize: ValueNotifier <double >(hasDragged
621
+ // Set the current size to the possibly updated initial size if the sheet
622
+ // hasn't changed yet.
623
+ currentSize: ValueNotifier <double >(hasChanged
595
624
? clampDouble (_currentSize.value, minSize, maxSize)
596
625
: initialSize),
597
626
hasDragged: hasDragged,
627
+ hasChanged: hasChanged,
598
628
);
599
629
}
600
630
}
@@ -785,6 +815,7 @@ class _DraggableScrollableSheetScrollController extends ScrollController {
785
815
void reset () {
786
816
extent._cancelActivity? .call ();
787
817
extent.hasDragged = false ;
818
+ extent.hasChanged = false ;
788
819
// jumpTo can result in trying to replace semantics during build.
789
820
// Just animate really fast.
790
821
// Avoid doing it at all if the offset is already 0.0.
0 commit comments