smooth_sheets
Sheet widgets with smooth motion and great flexibility
smooth_sheets package offers modal and persistent sheet widgets for Flutter apps. The key features are:
- Smooth motion: The sheets respond to user interaction with smooth, graceful motion.
- Highly flexible: Not restricted to a specific design. Both modal and persistent styles are supported, as well as scrollable and non-scrollable widgets.
- Supports nested navigation: A sheet is able to have multiple pages and to navigate between the pages with motion animation for transitions.
- Works with imperative & declarative Navigator API: No special navigation mechanism is required. The traditional ways such as
Navigator.push
is supported and it works with Navigator 2.0 packages like go_route as well.
Caution
This library is currently in the experimental stage. The API may undergo changes without prior notice.
Showcases
AI Playlist Generator
An AI assistant that helps create a music playlist based on the user's preferences. See the cookbook for more details.
Used components:
- NavigationSheet
- ModalSheetPage
- SheetContentScaffold
- SheetPhysics
Airbnb mobile app clone
A partial clone of the Airbnb mobile app. The user can drag the house list down to reveal the map behind it. See the cookbook for more details.
Used components:
- ScrollableSheet
- SheetPhysics
- SheetController
- SheetDraggable
- ExtentDrivenAnimation
Why use this?
There are few packages on pub.dev that supports nested navigation with motion animation for page transitions. One of the great choices for this usecase is wolt_modal_sheet, which this package is inspired by. Although smooth_sheet has similar features with wolt_modal_sheet, it does not intended to be a replacement of that package. Here is some differences between those 2 packages:
wolt_modal_sheetsmooth_sheetsDesignBased on Wolt's design guidelineNot restricted to a specific design, fully customizableNavigation mechanismManage the page index in ValueNotifierWorks with built-in Navigator API (both of imperative and declarative)Scrollable contentSupportedSupportedPersistent sheetsNot supportedSupportedScreen size adaptationThe sheet appears as a dialog on large screensNot supported
Usage
Several resources are available for learning the functionalities of this package.
- Tutorials: See cookbook/lib/tutorial/ to learn the basic usage of the core components.
- Showcases: More practical examples are available in cookbook/lib/showcase/.
- Documentation: WORK IN PROGRESS! Please see the source code for a while.
Ingredients
This section provides descriptions for each core component and links to related resources for further learning.
Extent
Extent represents the visible height of the sheet. It is used in a variety of situations, for example, to specify how much area of a sheet is initially visible at first build, or to limit the range of sheet dragging.
DraggableSheet
A sheet that can be dragged. The height will be equal to the content. The behavior of the sheet when over-dragged or under-dragged is determined by SheetPhysics. Note that this widget does not work with scrollable widgets. Instead, use ScrollableSheet for this usecase.
See also:
- draggable_sheet.dart for basic usage.
ScrollableSheet
A sheet that is similar to DraggableSheet, but specifically designed to be integrated with scrollable widgets. It will begin to be dragged when the content is over-scrolled or under-scrolled.
See also:
- scrollable_sheet.dart for basic usage.
NavigationSheet
A sheet that is able to have multiple pages and performs graceful motion animation when page transitions. It supports both of imperative Navigator API such as Navigator.push
, and declarative API (Navigator 2.0).
See also:
- declarative_navigation_sheet.dart, tutorial of integration with Navigator 2.0 using go_router package.
- imperative_navigation_sheet.dart, a tutorial of integration with imperative Navigator API.
ModalSheets
A sheet can be displayed as a modal sheet using ModalSheetRoute for imperative navigation, or ModalSheetPage for declarative navigation. A modal sheet offers the pull-to-dismiss action; the user can dismiss the sheet by swiping it down.
See also:
- declarative_modal_sheet.dart, a tutorial of integration with declarative navigation using go_router package.
- imperative_modal_sheet.dart, a tutorial of integration with imperative Navigator API.
SheetPhysics
A physics determines how the sheet will behave when over-dragged or under-dragged, or when the user stops dragging. There are 3 predefined physics:
- ClampingSheetPhysics: Prevents the sheet from reaching beyond the draggable bounds
- StretchingSheetPhysics: Allows the sheet to go beyond the draggable bounds, but then bounce the sheet back to the edge of those bounds
- SnappingSheetPhysics: Automatically snaps the sheet to a certain extent when the user stops dragging
These physics can be combined to create more complex behavior (e.g. stretching behavior + snapping behavior).
See also:
- sheet_physics.dart for basic usage.
SheetController
Like ScrollController for scrollable widget, the SheetController can be used to animate or observe the extent of a sheet.
See also:
- sheet_controller.dart for basic usage.
SheetContentScaffold
A special kind of Scaffold designed for use in a sheet. It has slots for an app bar and a sticky bottom bar, similar to Scaffold. However, it differs in that its height reduces to fit the content widget.
See also:
- sheet_content_scaffold.dart for basic usage.
SheetDraggable
SheetDraggable enables its child widget to act as a drag handle for the sheet. Typically, you will want to use this widget when placing non-scrollable widget(s) in a ScrollableSheet, since it only works with scrollable widgets, so you can't drag the sheet by touching a non-scrollable area. Try removing SheetDraggable and you will see that the drag handle doesn't work as it should. Note that SheetDraggable is not needed when using DraggableSheet since it implicitly wraps the child widget with SheetDraggable.
See also:
- sheet_draggable.dart for basic usage.
ExtentDrivenAnimation
It is easy to create sheet extent driven animations by using ExtentDrivenAnimation, a special kind of Animation whose value changes from 0 to 1 as the sheet extent changes from 'startExtent' to 'endExtent'.
See also:
- extent_driven_animation for basic usage.
- airbnb_mobile_app.dart, which show how ExtentDrivenAnimation can be used to hide the bottom navigation bar and a FAB when the sheet is dragged down, and to show them when the sheet is dragged up again.
Roadmap
- doc: Provide documentation
- doc: Add more showcases
- feat: Sheet decoration; a way to place an extra widget above the sheet
- feat: Provide a way to interrupt a modal route popping
- feat: Support shared appbars in NavigationSheet
- feat: Dispatch a Notification when the sheet extent changes
- feat: Implement modal sheet route adapted for iOS
Questions
If you have any questions, feel free to ask them on the discussions page.
Contributing
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.
If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". Don't forget to give the project a star! Thanks again!
- Fork the Project
- Create your Feature Branch (
git checkout -b feature/AmazingFeature
) - Commit your Changes (
git commit -m 'Add some AmazingFeature'
) - Push to the Branch (
git push origin feature/AmazingFeature
) - Open a Pull Request