stupid_simple_sheet 0.5.0 copy "stupid_simple_sheet: ^0.5.0" to clipboard
stupid_simple_sheet: ^0.5.0 copied to clipboard

A simple sheet widget for Flutter.

Stupid Simple Sheet #

Pub Version Coverage lintervention_badge Bluesky

A simple yet powerful sheet widget for Flutter with seamless scroll-to-drag transitions.

What makes it unique ✨ #

Smooth transitioning from any scrolling child to the drag gestures of the mobile sheet. The sheet automatically detects when scrollable content reaches its bounds and seamlessly transitions to sheet dragging behavior - no complex gesture coordination required.

Powered by Motor physics simulations to make the sheet feel incredibly natural and responsive. The spring physics create smooth, realistic motion that feels right at home on any device.

The sheet works perfectly with:

  • ListView
  • CustomScrollView
  • PageView
  • Any scrollable widget

⚠️ Important Warning #

Content inside the sheet should not define any custom ScrollConfiguration. The sheet relies on the default Flutter scroll behavior to properly detect scroll boundaries and transition between scrolling and dragging states.

Installation 💻 #

❗ In order to start using Stupid Simple Sheet you must have the Flutter SDK installed on your machine.

Install via flutter pub:

flutter pub add stupid_simple_sheet

Usage 🚀 #

Basic Sheet #

The basic sheet comes with very little styling.

You are responsible for wrapping your child in the appropriate shapes, paddings, SafeArea etc.

This might seem like a drawback, but it gives you all the freedom you could imagine.

Watch for example, how using a SingleChildScrollView effortlessly handles making overflowing content scrollable:

Resizing Sheet

import 'package:stupid_simple_sheet/stupid_simple_sheet.dart';

// Show a basic sheet
Navigator.of(context).push(
  StupidSimpleSheetRoute(
    child: YourSheetContent(),
  ),
);

Cupertino-style Sheet #

This library also provides a Cupertino-style modal sheet.

Cupertino Sheet

Navigator.of(context).push(
  StupidSimpleCupertinoSheetRoute(
    child: CupertinoPageScaffold(
      child: CustomScrollView(
        slivers: [
          CupertinoSliverNavigationBar(
            largeTitle: Text('Sheet'),
          ),
          SliverList(
            delegate: SliverChildBuilderDelegate(
              (context, index) => CupertinoListTile(
                title: Text('Item #$index'),
              ),
              childCount: 50,
            ),
          ),
        ],
      ),
    ),
  ),
);

Customizing Motion #

Navigator.of(context).push(
  StupidSimpleSheetRoute(
    motion: CupertinoMotion.bouncy(snapToEnd: true),
    child: YourContent(),
  ),
);

Programmatic Control with StupidSimpleSheetController #

You can programmatically control the sheet's position from within its content using the StupidSimpleSheetController. This is useful for implementing custom interactions, animations, or responding to user actions.

Navigator.of(context).push(
  StupidSimpleSheetRoute(
    child: Builder(
      builder: (context) {
        // Get the controller from the sheet context
        final controller = StupidSimpleSheetController.maybeOf<void>(context);
        
        return Column(
          children: [
            ElevatedButton(
              onPressed: () {
                // Animate to half-open position
                controller?.animateToRelative(0.5);
              },
              child: Text('Half Open'),
            ),
            ElevatedButton(
              onPressed: () {
                // Animate to fully open with snapping
                controller?.animateToRelative(0.8, snap: true);
              },
              child: Text('Almost Full (with snap)'),
            ),
            // Your other sheet content...
          ],
        );
      },
    ),
  ),
);

Controller Methods

  • maybeOf<T>(BuildContext context): Retrieves the controller from a context within the sheet. Returns null if called from outside a sheet.
  • animateToRelative(double position, {bool snap = false}): Animates the sheet to a relative position between 0.0 (closed) and 1.0 (fully open).
    • position: The target relative position (must be > 0.0 and ≤ 1.0)
    • snap: If true, snaps to the nearest configured snapping point after reaching the target

Note: The controller cannot close the sheet programmatically. To close the sheet, use Navigator.pop(context).

Custom Routes with Maximum Control #

For advanced use cases, you can create your own custom routes using the StupidSimpleSheetTransitionMixin for maximum control over the sheet behavior:

class MyCustomSheetRoute<T> extends PopupRoute<T>
    with StupidSimpleSheetTransitionMixin<T> {
  MyCustomSheetRoute({
    required this.child,
    this.motion = const CupertinoMotion.smooth(snapToEnd: true),
  });

  final Widget child;
  
  @override
  final Motion motion;

  @override
  Widget buildContent(BuildContext context) {
    // Build your custom sheet content with full control
    // For example you might want to render a background that extends past the bottom of the screen
    return SafeArea(
      bottom: false,
      child: Stack(
        children: [
          Positioned.fill(
            bottom: -1000,
            child: Material(
              borderRadius: BorderRadius.vertical(top: Radius.circular(12)),
            ),
          ),
          ClipRRect(
              borderRadius: BorderRadius.vertical(top: Radius.circular(12)),
              child: child,
          ),
        ],
      ),
    );
  }

  // Override any other properties for complete customization
  @override
  double get overshootResistance => 50; // Custom resistance
  
  @override
  Color? get barrierColor => Colors.black26;
}

This approach gives you complete control over the sheet's appearance, behavior, and physics while still benefiting from the smooth scroll-to-drag transitions.

Features 🎯 #

  • Seamless scroll transitions: Automatically handles the transition between scrolling content and sheet dragging
  • Spring physics: Natural motion using the motor package physics engine
  • Programmatic control: Use StupidSimpleSheetController to animate the sheet position from within its content
  • Customizable appearance: Control shape, clipping, and barrier properties
  • Cupertino integration: Works perfectly with Cupertino design components
  • Gesture coordination: No need to manually handle gesture conflicts
  • Multiple scroll types: Supports all Flutter scrollable widgets
  • Extensible architecture: Use the mixin to create custom routes with full control

Examples 📱 #

Check out the example app to see the sheet in action with:

  • Scrollable lists
  • Paged content with PageView
  • Dynamically resizing sheets
  • Different motion configurations