Some time ago I had to implement a bottom sheet that should be possible to expand or collapse by dragging just a header and a user shouldn’t be bound to some fixed height of that bottom sheet. First of all, I tried to use
DraggableScrollableSheet (a standard BottomSheet included in Flutter), but it turned out that it didn’t offer such behavior out of the box. The default use of
DraggableScrollableSheet has two problems:
- We can’t allow users to adjust the height of the bottom sheet freely. We can set
snapSizesparameter, which is a list of target sizes that the widget should snap to, but it’s not ideal.
- The bottom sheet can be dragged anywhere to expand or collapse it and we want to constrain that action only for a specific part of that sheet - the header.
A common use case for
Unfortunately on the internet, there is no clear solution on how to achieve the previous goals, so I want to share some with you 😀
So, our goal is to create something like the following:
So in the beginning, we have some logic inside
initState which is responsible for calculating the height of the bottom sheet’s header. As you can see, we use a
commentsHeaderKey key assigned on line 50 to the header widget. Thanks to that, we can get the height of our bottom sheet’s header. Later in the
build method on line 33, we use that height and
viewPadding (which shows us the size of the system’s UI like the status bar or system navigation) to calculate the
minChildSize for the
DraggableScrollableBottomSheet. As a result, the user sees only a header of our bottom sheet when the page is opened.
Then on line 42, we have to set the margin in order not to allow the bottom sheet to cover the system status bar at the top of the device. The previous line (41) is not required, it’s up to us which solution we prefer.
I think that the solution without a margin but with a higher header (to cover system navigation) would be the best. Something like that:
So, let’s back to the topic. The last very important thing is where we should put
scrollController received from
DraggableScrollableSheet’s builder method. That’s the tricky one because the first thing that comes to mind is just to pass it to the
ListView (or any scrollable widget) and that’s not something we want to do because we need to open/close the bottom sheet by dragging for a header and not list. That’s why on line 50, we pass it to
CommentsHeader widget. And then on line 81, we pass it to a scrollable widget connected just to the header and not the whole bottom sheet.
And I think that’s the main clue. As you can notice, it’s quite simple, but I was really struggling with it and that’s why this text has been written. For me from the future and for you, in order not to waste too much time on that 😁.
That was quite easy, right?
Do you know that the very first page that the user sees in your application is a Splash Screen? I explained how to easily add it to your app in my previous article. Check it out!
The full code presented in the following section can be found on my GitHub account here.