expressive_m3 0.2.0 copy "expressive_m3: ^0.2.0" to clipboard
expressive_m3: ^0.2.0 copied to clipboard

Material 3 Expressive design tokens, motion and widgets for Flutter — a shape-morphing loading indicator, pull-to-refresh, wavy progress gauge, spring transitions, expressive shapes and the full M3 ty [...]

example/lib/main.dart

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

void main() => runApp(const ExpressiveM3Demo());

class ExpressiveM3Demo extends StatelessWidget {
  const ExpressiveM3Demo({super.key});

  @override
  Widget build(BuildContext context) {
    final textTheme = ExpressiveTextTheme.base;
    return MaterialApp(
      title: 'expressive_m3',
      theme: ThemeData(
        useMaterial3: true,
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo),
        textTheme: textTheme,
        pageTransitionsTheme: expressivePageTransitionsTheme,
        extensions: <ThemeExtension<dynamic>>[
          EmphasizedTextTheme.of(textTheme),
        ],
      ),
      home: const _GalleryPage(),
    );
  }
}

class _GalleryPage extends StatefulWidget {
  const _GalleryPage();

  @override
  State<_GalleryPage> createState() => _GalleryPageState();
}

class _GalleryPageState extends State<_GalleryPage> {
  int _done = 2;
  static const int _total = 5;

  Future<void> _refresh() async {
    await Future<void>.delayed(const Duration(seconds: 2));
  }

  @override
  Widget build(BuildContext context) {
    final scheme = Theme.of(context).colorScheme;
    return Scaffold(
      appBar: AppBar(title: const Text('expressive_m3')),
      floatingActionButton: ExpressiveFabMenu(
        items: <ExpressiveFabMenuItem>[
          ExpressiveFabMenuItem(
            icon: const Icon(Icons.edit),
            label: 'Edit',
            onPressed: () {},
          ),
          ExpressiveFabMenuItem(
            icon: const Icon(Icons.share),
            label: 'Share',
            onPressed: () {},
          ),
        ],
      ),
      body: ExpressiveRefreshIndicator(
        onRefresh: _refresh,
        child: ListView(
          padding: const EdgeInsets.all(ExpressiveSpacing.lg),
          children: <Widget>[
            const _Section(
              title: 'Loading indicator',
              child: Row(
                spacing: ExpressiveSpacing.xl,
                children: <Widget>[
                  ExpressiveLoadingIndicator(),
                  ExpressiveLoadingIndicator(contained: true),
                ],
              ),
            ),
            _Section(
              title: 'Wavy progress',
              child: Row(
                spacing: ExpressiveSpacing.lg,
                children: <Widget>[
                  CircularWavyProgress(
                    value: _done / _total,
                    label: '$_done/$_total',
                    animationId: 'demo',
                  ),
                  FilledButton(
                    onPressed: () => setState(
                      () => _done = _done >= _total ? 0 : _done + 1,
                    ),
                    child: const Text('Advance'),
                  ),
                ],
              ),
            ),
            _Section(
              title: 'Pressable + expressive shape',
              child: PressableScale(
                child: Material(
                  color: scheme.secondaryContainer,
                  shape: const ExpressiveShapeBorder(ExpressiveShape.cookie),
                  child: const SizedBox(
                    width: 96,
                    height: 96,
                    child: Center(child: Icon(Icons.bolt_rounded)),
                  ),
                ),
              ),
            ),
            _Section(
              title: 'Button group',
              child: ExpressiveButtonGroup(
                children: <Widget>[
                  FilledButton(onPressed: () {}, child: const Text('Day')),
                  FilledButton(onPressed: () {}, child: const Text('Week')),
                  FilledButton(onPressed: () {}, child: const Text('Month')),
                ],
              ),
            ),
            _Section(
              title: 'Split button',
              child: ExpressiveSplitButton(
                label: const Text('Save'),
                onPressed: () {},
                menuChildren: <Widget>[
                  MenuItemButton(
                    onPressed: () {},
                    child: const Text('Save as draft'),
                  ),
                  MenuItemButton(
                    onPressed: () {},
                    child: const Text('Save a copy'),
                  ),
                ],
              ),
            ),
            _Section(
              title: 'Toolbar (floating)',
              child: ExpressiveToolbar(
                children: <Widget>[
                  IconButton(onPressed: () {}, icon: const Icon(Icons.undo)),
                  IconButton(onPressed: () {}, icon: const Icon(Icons.redo)),
                  IconButton(
                    onPressed: () {},
                    icon: const Icon(Icons.format_bold),
                  ),
                  IconButton(
                    onPressed: () {},
                    icon: const Icon(Icons.format_italic),
                  ),
                ],
              ),
            ),
            const _Section(
              title: 'Wavy progress',
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.stretch,
                spacing: ExpressiveSpacing.lg,
                children: <Widget>[
                  ExpressiveWavyLinearProgress(value: 0.6),
                  ExpressiveWavyLinearProgress(),
                  Align(
                    alignment: Alignment.centerLeft,
                    child:
                        ExpressiveWavyCircularProgress(value: 0.65, size: 64),
                  ),
                ],
              ),
            ),
            _Section(
              title: 'Emphasized type + numeric id',
              child: Text(
                'DR87 NMJ',
                style: context.emphasizedText.titleLarge.numericId,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class _Section extends StatelessWidget {
  const _Section({required this.title, required this.child});

  final String title;
  final Widget child;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(bottom: ExpressiveSpacing.xxl),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        spacing: ExpressiveSpacing.md,
        children: <Widget>[
          Text(title, style: Theme.of(context).textTheme.titleMedium),
          child,
        ],
      ),
    );
  }
}
2
likes
150
points
43
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Material 3 Expressive design tokens, motion and widgets for Flutter — a shape-morphing loading indicator, pull-to-refresh, wavy progress gauge, spring transitions, expressive shapes and the full M3 type/shape/spacing scales.

Repository (GitHub)
View/report issues

Topics

#material-design #material-3 #animations #ui #widget

License

MIT (license)

Dependencies

animations, flutter, material_new_shapes

More

Packages that depend on expressive_m3