Skip to content

Add drag length parameter to DraggableScrollableSheet #34111

Closed

Description

@blac3777

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.

Activity

  1. added
    p: material_uimaterial_ui package in flutter/packages
    f: scrollingViewports, list views, slivers, etc.
    on Jun 10, 2019
  2. tp commented on Jun 12, 2019

    @tp

    @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.)

  3. dnfield commented on Jul 15, 2019

    @dnfield
    Contributor

    You could add a notification listener above the scrollable sheet and do just that, right?

  4. tp commented on Jul 15, 2019

    @tp

    @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).

  5. dnfield commented on Jul 15, 2019

    @dnfield
    Contributor

    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...

  6. fralways commented on Sep 23, 2019

    @fralways

    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:

    1. Snapping with 3 posible heights
    2. In top part there should be non scrollable "handle", and everything bellow is scrollable

    Screen Shot 2019-09-23 at 2 27 45 PM

  7. added
    frameworkflutter/packages/flutter repository. See also f: labels.
    on Nov 26, 2019
  8. added
    customer: crowdAffects or could affect many people, though not necessarily a specific customer.
    c: new featureNothing broken; request for a new capability
    on Feb 27, 2020
  9. VladyslavBondarenko commented on Apr 22, 2020

    @VladyslavBondarenko

    Related to #45009

  10. added
    c: proposalA detailed proposal for a change to Flutter
    on Jul 8, 2020
  11. tzvc commented on Mar 28, 2021

    @tzvc

    Any updates on this? I feel like this is really needed since custom implementation with NotificationListener<DraggableScrollableNotification> is non-trivial.

  12. tzvc commented on Mar 28, 2021

    @tzvc

    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 ?

  13. caseycrogers commented on May 26, 2021

    @caseycrogers
    Contributor

    +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)

  14. caseycrogers commented on Jul 19, 2021

    @caseycrogers
    Contributor

    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.
  15. Alexays commented on Aug 8, 2021

    @Alexays
    Contributor

    @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 :)

  16. caseycrogers commented on Aug 8, 2021

    @caseycrogers
    Contributor

    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:

    • 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.

  17. Alexays commented on Aug 9, 2021

    @Alexays
    Contributor

    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!

  18. caseycrogers commented on Aug 11, 2021

    @caseycrogers
    Contributor

    For any interested, @Alexays and I wrote a proposal up for programmatic control. See the relevant issue and doc.

  19. dnfield commented on Aug 16, 2021

    @dnfield
    Contributor

    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?

  20. caseycrogers commented on Aug 16, 2021

    @caseycrogers
    Contributor

    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 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?

  21. dnfield commented on Aug 16, 2021

    @dnfield
    Contributor

    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.

  22. caseycrogers commented on Aug 16, 2021

    @caseycrogers
    Contributor

    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).

  23. github-actions commented on Sep 29, 2021

    @github-actions

    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.

  24. locked as resolved and limited conversation to collaborators on Sep 29, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    c: new featureNothing broken; request for a new capabilityc: proposalA detailed proposal for a change to Fluttercustomer: crowdAffects or could affect many people, though not necessarily a specific customer.f: scrollingViewports, list views, slivers, etc.frameworkflutter/packages/flutter repository. See also f: labels.p: material_uimaterial_ui package in flutter/packages

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions