You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Add drag length parameter to DraggableScrollableSheet #34111
I am currently using heavy packages like rubber, sliding_up_panel, stopper to implement what could be done w/ DraggableScrollableSheet if only it would snap open or closed upon drag release...
Only 1 new parameter would be needed: If null, the DraggableScrollableSheet would act as it does now; if set to a percentage of the parent, it would snap open or closed based on whether the threshold has been passed.
@blac3777 Have you tried adding something like this yourself?
I am currently exploring something similar, and I think the right place is goBallistic inside _DraggableScrollableSheetScrollPosition. But it seems so finely tuned, every change I make breaks some existing behavior. (For example I always end up in a state where interacting with the content of the sheet is not possible on the first tap, only on the second.)
We're currently running an internal fork of the sheet that exposes a ValueNotifier<double> which we use to be promptly informed when the sheet changes as well as to control the expansion of the sheet when we want to do so after some user interaction. (For example bouncing the sheet slightly to show that it's draggable.)
If you want I can share that approach, but I feel that it currently drills a little deep into the widget as it also affects _DraggableScrollableSheetScrollPosition / _DraggableSheetExtent).
So you should be able to just build the widget with a parent NotificationListener<DraggableScrollableNotification> and get all the information you need.
It's entirely possible we didn't document this properly...
For DraggableScrollableSheet to really be usable, especially in iOS apps, snap option is must have, and also additional check points for snapping would be good, not only min, max.
And finally for this to be complete all around solution I think adding optional non-scrollable widget on top is final touch.
Just for an example, my sheet has requirements which are missing in DraggableScrollableSheet:
Snapping with 3 posible heights
In top part there should be non scrollable "handle", and everything bellow is scrollable
Reacted by Dennis, Suneeth Lenin, miguelpruivo, Andres Michel, Guilherme C. Matuella, daveols, TurtleClaw Studios, Paul DeMarco, Simeon Akpanudo and Ritesh Singh
Any updates on this? I feel like this is really needed since custom implementation with NotificationListener<DraggableScrollableNotification> is non-trivial.
You could add a notification listener above the scrollable sheet and do just that, right?
@dnfield You mentioned getting the bubbling information using NotificationListener<DraggableScrollableNotification>. But how do you respond to this by controlling / animating the sheet to implement the extent "snap points"? Is that done via the passed ScrollController ?
I played around with a bunch of random apps that have scrollable bottom sheets, and not a single one doesn't exhibit snapping behavior. See: Github, Google Maps, Lyft, Youtube Music, Google Podcasts. The only use case that exists for this widget (from my quick survey) is not supported and requires some weird hackery to achieve (see #45009 as linked above) which I couldn't get to work without animation jank.
EDIT - more examples of scrollable bottom sheets with snapping behavior-I've yet to find one without:
Uber Eats, Google Photos, Facebook, Google Calendar, Trailforks, Android (the OS itself)
So I've got a PR (see above) that's almost done and ready for review (currently writing tests). I thought I'd swing back here and get folk's input on the behavior/API I've built.
In scope:
Adding snapping behavior to the DraggableScrollableSheet that can be enabled or disabled
Allowing users to specify what points to snap to
Out of scope (maybe visit in future PRs? Let me know what you're interested in and I'll try to get to it):
Programmatically moving or snapping the sheet
Customizing the snapping behavior (eg the logic for selecting which of the potential snap points to snap to)
API:
Added bool snap = false. If true, snapping behavior is enabled.
If false (default), the sheet behaves normally (this makes all changes non-breaking).
Added List<double>? snapSizes.
If snapping is enabled, snapSizes is used to determine what fractional values to snap to when snapping.
Must be in ascending order and be between (inclusive) minChildSize and maxChildSize. minChildSize and maxChildSize are always implicitly added to snapSizes, if not already present. eg if you specify snapSizes: [.5], the actual snap sizes will be: [<minChildSize>, .5, <maxChildSize>]. This is done to avoid awkward/undefined UX between snap sizes and the min and max sizes. intialChildSize may or may not be included in snapSizes and is not implicitly added.
Behavior (loosely modeled after example apps listed previously):
Snapping is triggered when the user's finger leaves the screen (as opposed to waiting for any leftover drag momentum to subside).
If the user's finger leaves the screen with a non-zero velocity, the sheet will snap to the next snap size in the velocity's direction. The snap will snap with a default speed, or the velocity's speed, whichever is greater (the default speed is to ensure that the snapping animation doesn't play uncomfortably slowly).
If the user's finger leaves the screen with zero velocity (within a tolerance), the sheet will snap to the nearest snap size, regardless of direction.
The sheet will not snap when built or reset (see DraggableScrollableSheet.reset(context)) even if the initialChildSize is not in snapSizes. Snapping will only be triggered after the sheet is dragged for the first time since creation or the last reset.
Reacted by Ritesh Singh
Reacted by Alexis Rouillard, Guillaume Roux and Ritesh Singh
@caseycrogers "Programmatically moving or snapping the sheet" This is what I was talking about in your PR.
I'm interested in this feature, I could start doing it, but I don't really see where to start, would it be with the actuator?
Otherwise thanks for your PR :)
As for programmatic snapping, i think there's a decision to make that's worth some discussion (maybe in discord, or in a proposal Google doc?).
We could either:
extend the current actuator
add a controller argument (maybe want to create an external controller that forwards commands to the existing private controller as the existing controller has a lot of methods inherited from ScrollController that might not really make sense in context).
add a controller argument and deprecate actuator, moving it's logic into controller using an inherited controller to support calling reset from arbitrary ancestor widgets (see NestedListView and ScrollController.absorb for an example).
My main issue with 1 is that the actuator feels really awkward and confusing to use. It's inconsistent with other common widgets such as ScrollView/ScrollController.
1 is the easiest, but imo is too confusing to be acceptable.
2 is reasonably easy, but now introduces two different ways of doing the same thing which is pretty non ideal.
3 is the cleanest but a lot of work and will require convincing others that this is the right approach (breaking change).
I'm a strong proponent of 3 (#embraceTheYakShave). I can write up an RFC on this to gather folks' input this week if you're fine to wait on things.
I'm also in favour of option 3 @caseycrogers
For the moment, I have made the DraggableSheetExtent class public and using updateExtent but it's not animated and not the best solution :D
c.f. https://github.com/caseycrogers/flutter/compare/snapping_sheet...PixelfApp:snapping_sheet?expand=1
I didn't want to push it further because it's a breaking change... but if you think the flutter team could accept a change like that.
Just sended you a ping on discord!
I think that it's worth providing a robust sheet widget in the framework because the framework is more discoverable and trusted by users (see attention on this issue and #45009), however I also see the argument for leaving this up to third party packages to reduce Flutter's maintenance burden. If we decide that third party packages are a better approach here, wouldn't that also mean we should probably delete ScrollableBottomSheet altogether? To reduce maintenance burden and, perhaps more importantly, stop confusing developers who come to the sheet and expect it to be robustly featured?
Is there an official Flutter guideline on how to decide what should and shouldn't be made first-party vs left to pub.dev?
To make it clear, I'm not suggesting that we can't or shouldn't support this - but I suppose it's good to have an idea of what's out there and what the API(s) look like. One thing that's slightly unfortunate in the community packages is the need to place the widget so high in the tree, although maybe that afford other design tradeoffs that we will now have to make here to support more features.
To make it clear, I'm not suggesting that we can't or shouldn't support this - but I suppose it's good to have an idea of what's out there and what the API(s) look like. One thing that's slightly unfortunate in the community packages is the need to place the widget so high in the tree, although maybe that afford other design tradeoffs that we will now have to make here to support more features.
Fair-my approach so far has been loosely informed by the third party packages (eg that's why I added the snapSizes argument).
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.
Activity
tp commentedon Jun 12, 2019
@blac3777 Have you tried adding something like this yourself?
I am currently exploring something similar, and I think the right place is
goBallisticinside_DraggableScrollableSheetScrollPosition. But it seems so finely tuned, every change I make breaks some existing behavior. (For example I always end up in a state where interacting with the content of the sheet is not possible on the first tap, only on the second.)dnfield commentedon Jul 15, 2019
You could add a notification listener above the scrollable sheet and do just that, right?
tp commentedon Jul 15, 2019
@dnfield You mean me or @blac3777 ?
We're currently running an internal fork of the sheet that exposes a
ValueNotifier<double>which we use to be promptly informed when the sheet changes as well as to control the expansion of the sheet when we want to do so after some user interaction. (For example bouncing the sheet slightly to show that it's draggable.)If you want I can share that approach, but I feel that it currently drills a little deep into the widget as it also affects
_DraggableScrollableSheetScrollPosition/_DraggableSheetExtent).dnfield commentedon Jul 15, 2019
The sheet already bubbles up changes using a https://api.flutter.dev/flutter/widgets/DraggableScrollableNotification/DraggableScrollableNotification.html
So you should be able to just build the widget with a parent
NotificationListener<DraggableScrollableNotification>and get all the information you need.It's entirely possible we didn't document this properly...
fralways commentedon Sep 23, 2019
For DraggableScrollableSheet to really be usable, especially in iOS apps, snap option is must have, and also additional check points for snapping would be good, not only min, max.
And finally for this to be complete all around solution I think adding optional non-scrollable widget on top is final touch.
Just for an example, my sheet has requirements which are missing in DraggableScrollableSheet:
VladyslavBondarenko commentedon Apr 22, 2020
Related to #45009
tzvc commentedon Mar 28, 2021
Any updates on this? I feel like this is really needed since custom implementation with
NotificationListener<DraggableScrollableNotification>is non-trivial.tzvc commentedon Mar 28, 2021
@dnfield You mentioned getting the bubbling information using
NotificationListener<DraggableScrollableNotification>. But how do you respond to this by controlling / animating the sheet to implement the extent "snap points"? Is that done via the passedScrollController?caseycrogers commentedon May 26, 2021
+100 to this request.
I played around with a bunch of random apps that have scrollable bottom sheets, and not a single one doesn't exhibit snapping behavior. See: Github, Google Maps, Lyft, Youtube Music, Google Podcasts. The only use case that exists for this widget (from my quick survey) is not supported and requires some weird hackery to achieve (see #45009 as linked above) which I couldn't get to work without animation jank.
EDIT - more examples of scrollable bottom sheets with snapping behavior-I've yet to find one without:
Uber Eats, Google Photos, Facebook, Google Calendar, Trailforks, Android (the OS itself)
caseycrogers commentedon Jul 19, 2021
So I've got a PR (see above) that's almost done and ready for review (currently writing tests). I thought I'd swing back here and get folk's input on the behavior/API I've built.
In scope:
Out of scope (maybe visit in future PRs? Let me know what you're interested in and I'll try to get to it):
API:
bool snap = false. If true, snapping behavior is enabled.If false (default), the sheet behaves normally (this makes all changes non-breaking).
List<double>? snapSizes.If snapping is enabled,
snapSizesis used to determine what fractional values to snap to when snapping.Must be in ascending order and be between (inclusive)
minChildSizeandmaxChildSize.minChildSizeandmaxChildSizeare always implicitly added tosnapSizes, if not already present. eg if you specifysnapSizes: [.5], the actual snap sizes will be:[<minChildSize>, .5, <maxChildSize>]. This is done to avoid awkward/undefined UX between snap sizes and the min and max sizes.intialChildSizemay or may not be included insnapSizesand is not implicitly added.Behavior (loosely modeled after example apps listed previously):
DraggableScrollableSheet.reset(context)) even if theinitialChildSizeis not insnapSizes. Snapping will only be triggered after the sheet is dragged for the first time since creation or the last reset.Alexays commentedon Aug 8, 2021
@caseycrogers "Programmatically moving or snapping the sheet" This is what I was talking about in your PR.
I'm interested in this feature, I could start doing it, but I don't really see where to start, would it be with the actuator?
Otherwise thanks for your PR :)
caseycrogers commentedon Aug 8, 2021
Np!
As for programmatic snapping, i think there's a decision to make that's worth some discussion (maybe in discord, or in a proposal Google doc?).
We could either:
ScrollControllerthat might not really make sense in context).resetfrom arbitrary ancestor widgets (seeNestedListViewandScrollController.absorbfor an example).My main issue with 1 is that the actuator feels really awkward and confusing to use. It's inconsistent with other common widgets such as
ScrollView/ScrollController.1 is the easiest, but imo is too confusing to be acceptable.
2 is reasonably easy, but now introduces two different ways of doing the same thing which is pretty non ideal.
3 is the cleanest but a lot of work and will require convincing others that this is the right approach (breaking change).
I'm a strong proponent of 3 (#embraceTheYakShave). I can write up an RFC on this to gather folks' input this week if you're fine to wait on things.
Alexays commentedon Aug 9, 2021
I'm also in favour of option 3 @caseycrogers
For the moment, I have made the DraggableSheetExtent class public and using updateExtent but it's not animated and not the best solution :D
c.f. https://github.com/caseycrogers/flutter/compare/snapping_sheet...PixelfApp:snapping_sheet?expand=1
I didn't want to push it further because it's a breaking change... but if you think the flutter team could accept a change like that.
Just sended you a ping on discord!
caseycrogers commentedon Aug 11, 2021
For any interested, @Alexays and I wrote a proposal up for programmatic control. See the relevant issue and doc.
dnfield commentedon Aug 16, 2021
I've recently become aware of https://pub.dev/packages/snapping_sheet - should we just focus on that one instead of futher extending the framework widget?
caseycrogers commentedon Aug 16, 2021
There's also https://pub.dev/packages/sliding_up_panel which is (AFAIK) the most popular and notably allows users to disable snapping. https://pub.dev/packages/rubber also exists with the added feature of "elastic" animations on drag (though I'm not sure these animations are good UX as they violate the Material Design gesture guidelines - see "Provide Realistic Responses").
I think that it's worth providing a robust sheet widget in the framework because the framework is more discoverable and trusted by users (see attention on this issue and #45009), however I also see the argument for leaving this up to third party packages to reduce Flutter's maintenance burden. If we decide that third party packages are a better approach here, wouldn't that also mean we should probably delete
ScrollableBottomSheetaltogether? To reduce maintenance burden and, perhaps more importantly, stop confusing developers who come to the sheet and expect it to be robustly featured?Is there an official Flutter guideline on how to decide what should and shouldn't be made first-party vs left to pub.dev?
dnfield commentedon Aug 16, 2021
To make it clear, I'm not suggesting that we can't or shouldn't support this - but I suppose it's good to have an idea of what's out there and what the API(s) look like. One thing that's slightly unfortunate in the community packages is the need to place the widget so high in the tree, although maybe that afford other design tradeoffs that we will now have to make here to support more features.
caseycrogers commentedon Aug 16, 2021
Fair-my approach so far has been loosely informed by the third party packages (eg that's why I added the
snapSizesargument).github-actions commentedon Sep 29, 2021
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of
flutter doctor -vand a minimal reproduction of the issue.