smooth_bottom_sheet 0.0.4 copy "smooth_bottom_sheet: ^0.0.4" to clipboard
smooth_bottom_sheet: ^0.0.4 copied to clipboard

Modern, animated and highly customizable bottom sheets for Flutter apps.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:smooth_bottom_sheet/smooth_bottom_sheet.dart';

void main() {
  runApp(const SmoothBottomSheetExampleApp());
}

class SmoothBottomSheetExampleApp extends StatefulWidget {
  const SmoothBottomSheetExampleApp({super.key});

  @override
  State<SmoothBottomSheetExampleApp> createState() =>
      _SmoothBottomSheetExampleAppState();
}

class _SmoothBottomSheetExampleAppState
    extends State<SmoothBottomSheetExampleApp> {
  ThemeMode _themeMode = ThemeMode.dark;

  void _toggleTheme() {
    setState(() {
      _themeMode =
          _themeMode == ThemeMode.dark ? ThemeMode.light : ThemeMode.dark;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'smooth_bottom_sheet example',
      themeMode: _themeMode,
      theme: ThemeData(
        colorSchemeSeed: const Color(0xFF0EA5E9),
        useMaterial3: true,
      ),
      darkTheme: ThemeData(
        colorSchemeSeed: const Color(0xFF7C3AED),
        useMaterial3: true,
        brightness: Brightness.dark,
      ),
      home: _ExampleHomePage(
        onToggleTheme: _toggleTheme,
        themeMode: _themeMode,
      ),
    );
  }
}

class _ExampleHomePage extends StatefulWidget {
  final VoidCallback onToggleTheme;
  final ThemeMode themeMode;

  const _ExampleHomePage({
    required this.onToggleTheme,
    required this.themeMode,
  });

  @override
  State<_ExampleHomePage> createState() => _ExampleHomePageState();
}

class _ExampleHomePageState extends State<_ExampleHomePage> {
  final SmoothBottomSheetController _controller = SmoothBottomSheetController();

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  void _openDefaultSheet() {
    showSmoothBottomSheet<void>(
      context: context,
      title: 'Smooth sheet',
      subtitle: 'Default adaptive style',
      child: const Text(
        'This is the default smooth bottom sheet. '
        'Use it for settings, confirmations and action menus.',
      ),
    );
  }

  void _openCustomizedSheet() {
    final isDark = widget.themeMode == ThemeMode.dark;
    showSmoothBottomSheet<void>(
      context: context,
      title: 'Custom style',
      subtitle: 'Theme + layout + animation',
      controller: _controller,
      theme: (isDark ? SmoothBottomSheetTheme.dark() : SmoothBottomSheetTheme.light())
          .copyWith(
        startColor: isDark ? const Color(0xFF1E1B4B) : const Color(0xFFEEF2FF),
        endColor: isDark ? const Color(0xFF0B1025) : const Color(0xFFE0E7FF),
        borderColor: isDark ? const Color(0x66A78BFA) : const Color(0x336366F1),
      ),
      layout: const SmoothBottomSheetLayout(borderRadius: 40, maxWidth: 560),
      animation: const SmoothBottomSheetAnimation(
        duration: Duration(milliseconds: 420),
        beginOffset: Offset(0, 0.14),
      ),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            'This sheet can be closed from inside or by controller.',
            style: TextStyle(
              color: isDark ? Colors.white70 : Colors.black87,
            ),
          ),
          const SizedBox(height: 16),
          FilledButton(
            onPressed: () => _controller.close(),
            child: const Text('Close with controller'),
          ),
        ],
      ),
    );
  }

  void _openScrollableSheet() {
    showSmoothBottomSheet<void>(
      context: context,
      title: 'Scrollable sheet',
      subtitle: 'Long content, capped at 80% height',
      scrollable: true,
      showHandle: true,
      maxHeightFactor: 0.8,
      child: _LongContent(),
    );
  }

  void _openGradientHeaderSheet() {
    showSmoothBottomSheet<void>(
      context: context,
      title: 'Gradient header',
      subtitle: 'Content scrolls under the faded header',
      gradientHeader: true,
      showHandle: true,
      maxHeightFactor: 0.8,
      child: _LongContent(),
    );
  }

  @override
  Widget build(BuildContext context) {
    final isDark = widget.themeMode == ThemeMode.dark;

    return Scaffold(
      appBar: AppBar(
        title: const Text('smooth_bottom_sheet'),
        actions: [
          IconButton(
            tooltip: isDark ? 'Light mode' : 'Dark mode',
            onPressed: widget.onToggleTheme,
            icon: Icon(isDark ? Icons.light_mode : Icons.dark_mode),
          ),
        ],
      ),
      body: Center(
        child: ConstrainedBox(
          constraints: const BoxConstraints(maxWidth: 420),
          child: Padding(
            padding: const EdgeInsets.all(24),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: [
                _SectionLabel('Standard'),
                const SizedBox(height: 8),
                FilledButton.tonal(
                  onPressed: _openDefaultSheet,
                  child: const Text('Default sheet'),
                ),
                const SizedBox(height: 8),
                FilledButton.tonal(
                  onPressed: _openCustomizedSheet,
                  child: const Text('Customized (theme + controller)'),
                ),
                const SizedBox(height: 20),
                _SectionLabel('Scrollable content'),
                const SizedBox(height: 8),
                FilledButton(
                  onPressed: _openScrollableSheet,
                  child: const Text('Scrollable — 80% height'),
                ),
                const SizedBox(height: 8),
                FilledButton(
                  onPressed: _openGradientHeaderSheet,
                  child: const Text('Gradient header — content scrolls under'),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

class _SectionLabel extends StatelessWidget {
  final String text;
  const _SectionLabel(this.text);

  @override
  Widget build(BuildContext context) {
    return Text(
      text.toUpperCase(),
      style: Theme.of(context).textTheme.labelSmall?.copyWith(
        letterSpacing: 1.2,
        fontWeight: FontWeight.w700,
        color: Theme.of(context).colorScheme.primary,
      ),
    );
  }
}

class _LongContent extends StatelessWidget {
  const _LongContent();

  @override
  Widget build(BuildContext context) {
    final color = Theme.of(context).colorScheme.primary;
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        for (int i = 1; i <= 14; i++) ...[
          Container(
            padding: const EdgeInsets.all(16),
            decoration: BoxDecoration(
              color: color.withValues(alpha: 0.06),
              borderRadius: BorderRadius.circular(14),
              border: Border.all(color: color.withValues(alpha: 0.12)),
            ),
            child: Row(
              children: [
                Container(
                  width: 36,
                  height: 36,
                  alignment: Alignment.center,
                  decoration: BoxDecoration(
                    color: color.withValues(alpha: 0.14),
                    shape: BoxShape.circle,
                  ),
                  child: Text(
                    '$i',
                    style: TextStyle(
                      color: color,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                ),
                const SizedBox(width: 14),
                Expanded(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        'Item $i',
                        style: const TextStyle(fontWeight: FontWeight.w600),
                      ),
                      const SizedBox(height: 2),
                      Text(
                        'Scroll up — watch this item slide under the gradient header.',
                        style: Theme.of(context).textTheme.bodySmall,
                      ),
                    ],
                  ),
                ),
              ],
            ),
          ),
          if (i < 14) const SizedBox(height: 10),
        ],
        const SizedBox(height: 8),
      ],
    );
  }
}
1
likes
160
points
178
downloads

Documentation

API reference

Publisher

verified publishereliazavatta.it

Weekly Downloads

Modern, animated and highly customizable bottom sheets for Flutter apps.

Repository (GitHub)
View/report issues

Topics

#bottom-sheet #animations #ui #flutter-widgets #smooth

License

MIT (license)

Dependencies

flutter

More

Packages that depend on smooth_bottom_sheet