Skip to content

Can't swipe to dismiss scrollable Bottom Sheet #36283

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
cpboyd opened this issue Jul 16, 2019 · 43 comments
Open

Can't swipe to dismiss scrollable Bottom Sheet #36283

cpboyd opened this issue Jul 16, 2019 · 43 comments
Labels
c: new feature Nothing broken; request for a new capability c: proposal A detailed proposal for a change to Flutter customer: crowd Affects or could affect many people, though not necessarily a specific customer. f: gestures flutter/packages/flutter/gestures repository. f: material design flutter/packages/flutter/material repository. f: scrolling Viewports, list views, slivers, etc. framework flutter/packages/flutter repository. See also f: labels. P2 Important issues not at the top of the work list team-design Owned by Design Languages team triaged-design Triaged by Design Languages team

Comments

@cpboyd
Copy link

cpboyd commented Jul 16, 2019

Per @dnfield #31739 (comment)

Use case

See the Crane Material sample and Google I/O 2019

These both feature a bottom sheet that slides up (in the case of I/O, you select "Events" and the hit the "Filter" FAB) and scrolls.

With the I/O app, if you continue to swipe down when scrolled to the top, it will start to drag and then dismiss when a threshold is reached.

If the threshold is not reached (or you swipe upwards) then the bottom sheet will not be dismissed and it'll rebound to the top of the screen.

Proposal

I'd think this should be a part of DraggableScrollableSheet as mentioned in #31739, but maybe it makes sense to bake the logic into the Bottom Sheet itself?

I've tried both modal and non-modal bottom sheets with and without the DraggableScrollableSheet, and can't seem to make this work as is.

The current issue with the DraggableScrollableSheet is that you can't have the sheet be maximized all the time. (Since, as I mentioned in #31739 (comment), any swipe will immediately dismiss the BottomSheet rather than scroll the CustomScrollView)

@dnfield dnfield added f: gestures flutter/packages/flutter/gestures repository. f: material design flutter/packages/flutter/material repository. f: scrolling Viewports, list views, slivers, etc. framework flutter/packages/flutter repository. See also f: labels. labels Jul 16, 2019
@dnfield dnfield added this to the Goals milestone Jul 16, 2019
@dnfield
Copy link
Contributor

dnfield commented Jul 16, 2019

It would be super helpful if you had a gif/youtube/video of this behavior. I think I know what you're talking about, but I haven't used the apps you're referring to and I'm not sure which part to look for.

@cpboyd
Copy link
Author

cpboyd commented Jul 16, 2019

@dnfield See https://www.youtube.com/watch?v=95MUkecOta4

I wasn't able to get it to "rebound" while recording, but I'm pretty sure I've seen it bounce back to the top if a certain threshold isn't met.

Edit: First dismiss is dragging from the app bar. Second dismiss is from dragging the list after reaching the top (similar behavior to DraggableScrollableSheet). I had to release (after reaching the top of the list) and then drag down again.

@dnfield
Copy link
Contributor

dnfield commented Jul 16, 2019

I thought the bottom sheet was working this way - the first time you hit the top of the list it will bounce, the second time it will actually drag down. I feel like I'm missing something in the desired behavior though.

@cpboyd
Copy link
Author

cpboyd commented Jul 17, 2019

@dnfield I've tried both

        _scaffoldKey.currentState.showBottomSheet(
          _buildBottomSheet,
        );

and

        showModalBottomSheet(
          context: context,
          builder: _buildBottomSheet,
          isScrollControlled: true,
        );

where _buildBottomSheet is a Widget Function(BuildContext) that contains a CustomScrollView.

Nothing seems to do the drag-to-dismiss except when wrapped in a DraggableScrollableSheet.

Do I need to pass in a special ScrollController?

@dnfield
Copy link
Contributor

dnfield commented Jul 17, 2019

You have to use a DraggableScrollableSheet for that behavior to work.

@cpboyd
Copy link
Author

cpboyd commented Jul 17, 2019

@dnfield Ok. So how do I get the DraggableScrollableSheet to rebound back to maxChildSize unless the minChildSize threshold is passed?

I'm currently using this:

DraggableScrollableSheet(
      builder: scroll,
      initialChildSize: 1.0,
      minChildSize: 0.9,
    );

Unfortunately, the user can wind up with it sticking between 1.0 and 0.9, which looks a little awkward.

@dnfield
Copy link
Contributor

dnfield commented Jul 17, 2019

Unfortunately this isn't really documented well at all, and in trying to do it I'm finding some other bugs.

I think this should be possible, but it may take me a little while to get back to it. If you have a proposal for fixing it we could review a PR for it as well.

@rbluethl
Copy link

rbluethl commented Feb 7, 2020

Are there any updates on this?

@jamesblasco
Copy link
Contributor

jamesblasco commented Apr 15, 2020

Hello @rbluethl, I built a package that supports scrollable ModalBottomSheets.
https://github.com/jamesblasco/modal_bottom_sheet

Instead of showModalBottomSheet, it would be:

showMaterialModalBottomSheet(
  context: context,
  builder: (context, scrollController) => Container(),
})

Hope it can help you until this is officially implemented.

@ksankumar
Copy link

Any update on this?
showModalBottomSheet not able to dismiss when swipe down.

@kf6gpe kf6gpe added the P2 Important issues not at the top of the work list label May 29, 2020
@iapicca iapicca added has reproducible steps The issue has been confirmed reproducible and is ready to work on c: new feature Nothing broken; request for a new capability labels Jul 8, 2020
@VladyslavBondarenko VladyslavBondarenko removed the has reproducible steps The issue has been confirmed reproducible and is ready to work on label Jul 31, 2020
@Hixie Hixie removed this from the None. milestone Aug 17, 2020
@zeletrik
Copy link

Any news on this?

@prayatna
Copy link

prayatna commented Apr 8, 2021

Hello @rbluethl, I built a package that supports scrollable ModalBottomSheets.
https://github.com/jamesblasco/modal_bottom_sheet

Instead of showModalBottomSheet, it would be:

showMaterialModalBottomSheet(
  context: context,
  builder: (context, scrollController) => Container(),
})

Hope it can help you until this is officially implemented.

I tried using this plugin, happen to fix the issue of dismiss on scroll; but it goes over the app bar when the scrollable body is too long like I found here

@jamesblasco
Copy link
Contributor

Hey, @pranayairan your issue is a bit off-topic. For issues related to the package use https://github.com/jamesblasco/modal_bottom_sheet/issues/add

I will be happy to help you there solve this 🙂

@lbFlyBoy
Copy link

officially update on this ?

@eli1stark
Copy link

Hello @rbluethl, I built a package that supports scrollable ModalBottomSheets. https://github.com/jamesblasco/modal_bottom_sheet

Instead of showModalBottomSheet, it would be:

showMaterialModalBottomSheet(
  context: context,
  builder: (context, scrollController) => Container(),
})

Hope it can help you until this is officially implemented.

Unfortunately, the package has some bugs and looks like it's not maintained anymore. The official fix is needed.

@jeffaknine
Copy link

I've managed to do it with the following :

showModalBottomSheet(
  shape: RoundedRectangleBorder(
    borderRadius: BorderRadius.circular(16),
  ),
  isScrollControlled: true,
  isDismissible: true,
  context: context,
  builder: (context){
    return  DraggableScrollableSheet(
        expand: false,
        initialChildSize: 1,
        // minChildSize: 1,
        snap: true,
        builder: (context, scrollController) {
          return SingleChildScrollView(
            controller: scrollController,
            children:[],
          );
        },
    );
  },
);

@mohitra0
Copy link

facing the same issue. do mention me once fixed

@abhinandan-chakraborty
Copy link

Crazy how flutter team couldn't provide an official fix for this since last 4 year.

@vishalpatel1327
Copy link

Any updates on the longest survival issue?

@EvanSmith93
Copy link

EvanSmith93 commented May 27, 2023

Untitled.mp4

I'm also having this issue. Once the content in the bottom sheet becomes longer than the screen (when I open the keyboard), I can't dismiss by swiping the main content (even once the content is shorter). Then I can only dismiss the bottom sheet by swiping the top handle or tapping outside the sheet. A fix for this would be much appreciated!

@julianniedermaier
Copy link

julianniedermaier commented Jun 2, 2023

A temporary fix I am currently using is:

bool bottomSheetOpen = true;
await showModalBottomSheet(
    context: context,
    isScrollControlled: true,
    enableDrag: false,
    useSafeArea: true,
    builder: (BuildContext context) {
      return NotificationListener<DraggableScrollableNotification>(
        onNotification: (notification) {
          if (notification.extent <= 0.1 && bottomSheetOpen == true) {
            //close the modal bottom sheet if the draggable scrollable sheet
            //size is below 0.1, but the modal bottom sheet closing has not
            //been triggered
            Navigator.of(context).pop();
            return true;
          } else {
            return false;
          }
        },
        child: DraggableScrollableSheet(
          initialChildSize: 0.4,
          maxChildSize: 1.0,
          minChildSize: 0.0,
          snap: true,
          snapSizes: const [0.4],
          expand: false,
          builder: (BuildContext context, ScrollController controller) {
            return Container(
...
bottomSheetOpen = false;

The NotificationListener here forcefully closes the bottom sheet if the close modal bottom sheet has not been triggered. Works quite well, but is obviously a bit of a dirty solution

@tmaihoff
Copy link

tmaihoff commented Oct 7, 2023

any updates here?
I have scrollable content in my ModalBottomSheet. When I swipe down to scroll to the top, I'd expect that another swipe closed the modal but this does not work. I just get the stretching animation that the end of the scrollable content is reached.

@Anikets08
Copy link

any updates here? I have scrollable content in my ModalBottomSheet. When I swipe down to scroll to the top, I'd expect that another swipe closed the modal but this does not work. I just get the stretching animation that the end of the scrollable content is reached.

Tried this workaround https://github.com/Anikets08/bottomSheet-listview-scroll-to-dismiss/blob/main/lib/main.dart, probably could help you

@aytunch
Copy link

aytunch commented Oct 7, 2023

@Anikets08 in the example you provided, author uses shrinkWrap: true which defeats the purpose of ListView.builder. So this would not be a performant option. Maybe only for small number of items.

@ondanplatform
Copy link

any update?

@anhlee99
Copy link

anhlee99 commented Dec 10, 2023

Screenshot 2023-12-10 at 18 33 43

hope it helps you

@vongrad
Copy link

vongrad commented Dec 27, 2023

Any update on this? It seems like a very basic feature that Flutter should support.

@FrenkyDema
Copy link

FrenkyDema commented Jan 29, 2024

Screenshot 2023-12-10 at 18 33 43

hope it helps you

This solves my problem with the same problem, thanks 👍

@tmaihoff
Copy link

Screenshot 2023-12-10 at 18 33 43

hope it helps you

Appreciate your effort but why would you post code as a screenshot 👀

@FrenkyDema
Copy link

FrenkyDema commented Jan 30, 2024

Screenshot 2023-12-10 at 18 33 43
hope it helps you

Appreciate your effort but why would you post code as a screenshot 👀

Take:

showModalBottomSheet<void>(
  context: context,
  isScrollControlled: true,
  builder: (context) => DraggableScrollableSheet(
    expand: false,
    initialChildSize: 0.95,
    minChildSize: 0.5,
    maxChildSize: 0.95,
    builder: (BuildContext context, ScrollController scrollController) {
      return Container(
        color: Colors.white,
        child: SingleChildScrollView(
          controller: scrollController,
          child: Container(
            padding: const EdgeInsets.all(10.0),
            child: Column(
              children: [
                for (int i = 0; i < 200; i++)
                  SizedBox(
                    height: 50.0,
                    width: double.infinity,
                    child: Container(
                      color: Colors.grey,
                      child: Text("data ${i}"),
                    ),
                  ),
              ],
            ),
          ),
        ),
      );
    },
  ),
);

@kanhaiyabigbasket
Copy link

any update?

@notsag-dev
Copy link

notsag-dev commented Jul 28, 2024

For those looking for at least a workaround for not being able to hide the bottom sheet by dragging it down when the inner list size exceeds the size of the bottom sheet: Pop the context from the inner list (this makes the bottom sheet hide), when there's a top overscroll on that list and the user is currently dragging.

This doesn't progressively hides the bottom sheet when you drag it down, but it detects the gesture and hides it all at once. This is the closest I was able to get to an acceptable behavior, while still being a patch. For the case in which the inner list is smaller than the outer sheet it does work as expected.

My bottom sheet:

  showModalBottomSheet(
    context: context,
    enableDrag: true,
    isScrollControlled: true,
    builder: (BuildContext context) {
      return FractionallySizedBox(
          heightFactor: 0.9,
          child: DraggableScrollableSheet(
            maxChildSize: 1,
            minChildSize: 1,
            initialChildSize: 1,

The inner scrollable widget needs these state fields:

  final ScrollController scrollController = ScrollController();
  bool isAtTop = true;
  bool userIsDragging = true;

Add listener in the initState for the scroll:

    scrollController.addListener(scrollListener);

The listener detects when you are at the top of the list:

  void scrollListener() {
    setState(() {
      isAtTop = scrollController.offset <= 0;
    });

And in the build method use a NotificationListener to detect also when the user is currently dragging and the top overscroll is less than a certain value (-3 in this case), the context is popped and the bottom sheet hides:

NotificationListener<ScrollNotification>(
    onNotification: (ScrollNotification scrollNotification) {
      if (scrollNotification is ScrollStartNotification) {
        if (isAtTop &&
            scrollNotification.dragDetails != null) {
          userIsDragging = true;
        }
      } else if (scrollNotification
          is ScrollEndNotification) {
        userIsDragging = false;
      } else if (scrollNotification
          is OverscrollNotification) {
        if (isAtTop &&
            userIsDragging &&
            scrollNotification.overscroll < -3) {
          Navigator.pop(context);
          return true;
        }
      }
      return false;
    },
    child: PagedListView<int, Comment>(
        pagingController: pagingController,
        scrollController: scrollController,
        physics: const ClampingScrollPhysics(),
        primary: false,
        shrinkWrap: true,
        ...

I hope this helps until we have a proper solution.

Note: If you wonder why the drag event is needed: You don't want the momentum of the scroll up to hide your bottom sheet. This also causes a top overscroll < 0 when it reaches the beginning of the list.

Edit: It's necessary to set ClampingScrollPhysics for the list physics as for iOS the default is BouncingScrollPhysics and the overscroll notification doesn't work in that case.

@ziqq
Copy link
Contributor

ziqq commented Jul 31, 2024

The solution is not quite correct and requires improvements from the flutter team. The point is that when the scroll ends and the top of the screen is reached, the bottom sheet closes immediately, which does not meet expectations.

Use mobile breackpoint: https://dartpad.dev/?id=ee0a9552f654de9fe24adbbdba95fc2a

Expected: https://github.com/user-attachments/assets/964d906c-2b0e-45be-be4d-bfeb3ba0d5fc

In fakt: https://github.com/user-attachments/assets/eb886651-5f5e-419f-ad21-98dfc0cdfa21

@notsag-dev
Copy link

This isn't an actual solution but a patch as I said. For my use case this is better than having a bottom sheet that can only be dismissed from the handle when the inner list exceeds the bottom sheet size. I'm also looking forward to an actual solution.

@shahmirzali49
Copy link

any update?

@JunseungBaek
Copy link

This is the exact same behavior as YouTube comments. Hope this gets resolved soon.

@rydmike
Copy link
Contributor

rydmike commented Mar 15, 2025

Drag to dismiss scrollable bottom sheet?

The bottom sheet is not necessarily limited to Material design, however even the Material specification refers to being able to swipe down to dismiss a sheet, here:

https://m3.material.io/components/bottom-sheets/guidelines#22deb8a2-3513-4a2e-aa47-c64875e15e12

Image

Currently this is not possible in Flutter when we have a sheet with scrolling content, as all in this thread have experienced. At least it is not possible not without some quite hacky and/or poorly working solutions. If anybody has a well working simple solution please do share it.

Predictive back (Android & Material-3)

A new thing in Material-3 is the predictive back swipe that also allows you to close a bottom sheet. This is something that is also not yet supported, especially with the sheet shrink animation.

It is shown and demonstrated here:

https://m3.material.io/components/bottom-sheets/guidelines#3d7735e2-73ea-4f3e-bd42-e70161fc1085

lvpbtr1r-GM3-Components-BottomSheets-Guidelines-2-v01.mp4

Flutter does not support this pattern either.

Both these cases should of course have easy built-in support in Flutter. For the first case it has been open since 2019, without any good or well known solution, which is quite sad, the second case is still quite a new pattern so that is more understandable, most native Android apps do not support it yet either.

@blehn
Copy link

blehn commented May 14, 2025

Been working on a Flutter project for about a month. Going to have rebuild the whole thing in Swift specifically because of this issue. 6 years and no attention from the official team.

Warning: do not use Flutter for serious applications. You will get burned eventually.

@tmaihoff
Copy link

For the ios version of my app I use this package https://pub.dev/packages/modal_bottom_sheet where the function works just as intended. There, I can scroll down to dismiss the sheet.

I haven't had the time to investigate and compare the code, but maybe we could find a potential solution there as well.

@blehn and maybe this package could be an option for you as well before you rewrite everything.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c: new feature Nothing broken; request for a new capability c: proposal A detailed proposal for a change to Flutter customer: crowd Affects or could affect many people, though not necessarily a specific customer. f: gestures flutter/packages/flutter/gestures repository. f: material design flutter/packages/flutter/material repository. f: scrolling Viewports, list views, slivers, etc. framework flutter/packages/flutter repository. See also f: labels. P2 Important issues not at the top of the work list team-design Owned by Design Languages team triaged-design Triaged by Design Languages team
Projects
None yet
Development

No branches or pull requests