smooth_sheets

repository·main·Indexed 19 days ago

https://github.com/fujidaiti/smooth_sheets

A Flutter package for creating highly customizable, smooth-motion modal and persistent sheets. It supports nested navigation, works with both imperative and declarative Navigator APIs (including go_router), and includes support for iOS 15-style modal sheets. Key components include the Sheet widget for draggable content, PagedSheet for multi-page stacks, and SheetContentScaffold for structured layouts with top and bottom bars.

Tokens
16.1K
Snippets
51
Records
76
Agent score
66%

What's inside smooth_sheets

  1. Overview of smooth_sheets

    main

    smooth_sheets

    smooth_sheets is a Flutter package providing modal and persistent sheet widgets designed for smooth, graceful motion and high flexibility.

    Key Capabilities:

    • Smooth Motion: High-quality interaction response.
    • Flexible Design: Supports both modal and persistent styles, as well as scrollable and non-scrollable content without design restrictions.
    • Nested Navigation: Supports sheets with multiple pages and motion-animated transitions between them.
    • Navigator Compatibility: Works seamlessly with both the imperative Navigator API (Navigator.push) and declarative Navigator 2.0 APIs (e.g., go_router).
    • iOS Style: Includes support for iOS 15-style modal sheets.
  2. Configure SheetPhysics and SheetSnapGrid

    main

    Sheet behavior is controlled by two distinct mechanisms:

    1. SheetPhysics: Determines how the sheet behaves during over-dragging, under-dragging, or when the user stops dragging (e.g., momentum/friction). This is independent of snapping.
    2. SheetSnapGrid: Determines the specific offsets to which the sheet snaps when the user stops dragging or when an animation completes.
  3. How SheetViewport and Padding work

    main

    In v0.11.x, SheetViewport is a required component for non-modal sheets. Modal sheets (like those using ModalSheetRoute or ModalSheetPage) create a SheetViewport internally and do not require you to wrap them manually.

    Adding Padding

    You can add transparent space around a sheet using the padding property on SheetViewport for regular sheets, or the viewportPadding property on modal routes.

    // For Regular Sheets
    SheetViewport(
      padding: EdgeInsets.all(10),
      child: Sheet(...),
    )
    
    // For Modal Sheets
    ModalSheetRoute(
      viewportPadding: EdgeInsets.only(
        top: MediaQuery.viewPaddingOf(context).top,
        bottom: 10,
        left: 10,
        right: 10,
      ),
      builder: (context) => Sheet(...),
    );
  4. Manage navigation with PagedSheet

    main

    Use PagedSheet to manage a stack of pages within a single sheet, allowing for transitions between them. It integrates with Flutter's Navigator API for both imperative (Navigator.push) and declarative (e.g., go_router, auto_route) navigation.

    Each page in the stack is defined using a PagedSheetPage, which allows for per-page configurations such as:

    • initialOffset
    • snapGrid
    • scrollConfiguration
    • Custom transitions (defaults to the application's theme)
  5. Understand the terminology shift to 'Offset'

    main

    The v0.11.x API has standardized terminology around the concept of Offset to replace inconsistent terms like 'extent', 'position', and 'anchor'.

    Old Term (v0.10.x)New Term (v0.11.x)
    ExtentOffset
    SheetAnchorSheetOffset
    extent-drivenoffset-driven
    minPosition / maxPositionManaged via snapGrid or SheetOffset
  6. Compare smooth_sheets with wolt_modal_sheet

    main

    If you are deciding between smooth_sheets and wolt_modal_sheet, consider these differences:

    Featurewolt_modal_sheetsmooth_sheets
    DesignBased on Wolt's design guidelinesNot restricted; fully customizable
    NavigationRequires managing page index in ValueNotifierWorks with built-in Navigator API (Imperative & Declarative)
    Scrollable ContentSupportedSupported
    Persistent SheetsNot supportedSupported
    Screen Size AdaptationAppears as a dialog on large screensNot supported
  7. Configure snapping behavior with SnapToNearest

    main

    Starting from version 0.3.x, SnapToNearest can no longer be declared as a const due to performance optimizations.

    If you want the sheet to snap only to the minimum and maximum pixel boundaries, it is recommended to use SnapToNearestEdge instead of SnapToNearest, as it is more simplified and performant.

    When using SnapToNearest with specific extents, ensure the parent physics object is not marked as const.

    physics: StretchingSheetPhysics(
      parent: SnappingSheetPhysics(
        snappingBehavior: SnapToNearest(
          snapTo: [
            const Extent.proportional(0.2),
            const Extent.proportional(0.5),
            const Extent.proportional(1),
          ],
        ),
      ),
    ),
  8. Migrate from StretchingSheetPhysics to BouncingSheetPhysics

    main

    In version 0.8.0 and later, StretchingSheetPhysics was renamed to BouncingSheetPhysics to more accurately describe its behavior (allowing the sheet position to exceed content bounds without resizing the sheet). All related classes and properties were renamed accordingly. To migrate, replace any usage of StretchingSheetPhysics with BouncingSheetPhysics and update the configuration of the bounce range.

    // BEFORE (0.7.x)
    const physics = StretchingSheetPhysics(
      stretchingRange: Extent.proportional(0.1),
    );
    
    // AFTER (0.8.x+)
    const physics = BouncingSheetPhysics(
      behavior: FixedBouncingBehavior(Extent.proportional(0.1)),
    );
  9. Enable swipe-to-dismiss on modal sheets

    main

    In version 0.6.0 and later, the SheetDismissible widget has been removed. To enable swipe-to-dismiss functionality on a modal sheet, set the swipeDismissible property to true on your route (e.g., ModalSheetRoute, ModalSheetPage, or CupertinoModalSheetRoute).

    To handle dismissal logic (such as showing a confirmation dialog before the sheet closes), use Flutter's native PopScope widget wrapping your sheet content. This allows you to intercept swipe-to-dismiss gestures, modal barrier taps, and system back gestures in a single location.

    // Enable swipe-to-dismiss via the route property
    ModalSheetRoute(
      swipeDismissible: true,
      builder: (context) {
        return PopScope(
          canPop: false,
          onPopInvoked: (didPop) {
            if (didPop) return;
            // Handle dismissal logic here (e.g., show confirmation dialog)
          },
          child: DraggableSheet(...),
        );
      },
    );