m3e_card_list 0.0.1 copy "m3e_card_list: ^0.0.1" to clipboard
m3e_card_list: ^0.0.1 copied to clipboard

A Flutter package providing expressive Material 3 card lists with dynamically rounded corners for ListView, SliverList and Column.

example/lib/main.dart

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

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

final ValueNotifier<ThemeMode> themeNotifier = ValueNotifier(ThemeMode.system);

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

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder<ThemeMode>(
      valueListenable: themeNotifier,
      builder: (context, ThemeMode currentMode, _) {
        return MaterialApp(
          debugShowCheckedModeBanner: false,
          title: 'M3E Card List Demo',
          themeMode: currentMode,
          theme: ThemeData(
            colorScheme: ColorScheme.fromSeed(
              seedColor: Colors.deepPurple,
              brightness: Brightness.light,
            ),
            useMaterial3: true,
          ),
          darkTheme: ThemeData(
            colorScheme: ColorScheme.fromSeed(
              seedColor: Colors.deepPurple,
              brightness: Brightness.dark,
            ),
            useMaterial3: true,
          ),
          home: const ExampleHomePage(),
        );
      },
    );
  }
}

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

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

class _ExampleHomePageState extends State<ExampleHomePage> {
  int _currentIndex = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Theme.of(context).colorScheme.surfaceContainerLowest,
      appBar: AppBar(
        title: Text(
          _currentIndex == 0 ? 'Normal M3ECardList' : 'SliverM3ECardList',
        ),
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        actions: [
          IconButton(
            icon: Icon(
              Theme.of(context).brightness == Brightness.light
                  ? Icons.dark_mode
                  : Icons.light_mode,
            ),
            onPressed: () {
              themeNotifier.value =
                  Theme.of(context).brightness == Brightness.light
                  ? ThemeMode.dark
                  : ThemeMode.light;
            },
          ),
        ],
      ),
      body: _currentIndex == 0
          ? const NormalListExample()
          : const SliverListExample(),
      bottomNavigationBar: NavigationBar(
        selectedIndex: _currentIndex,
        onDestinationSelected: (index) {
          setState(() {
            _currentIndex = index;
          });
        },
        destinations: const [
          NavigationDestination(icon: Icon(Icons.list), label: 'Normal'),
          NavigationDestination(icon: Icon(Icons.layers), label: 'Sliver'),
        ],
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return ListView(
      padding: const EdgeInsets.all(16.0),
      children: [
        _buildSectionHeader(context, 'Single Item (Data 1)'),
        M3ECardList(
          itemCount: 1,
          border: BorderSide(color: Theme.of(context).colorScheme.primary),
          itemBuilder: (context, index) =>
              _buildListItem(context, 1, onTap: false),
          elevation: 4,
        ),
        const SizedBox(height: 24),

        _buildSectionHeader(context, 'Two Items (Data 2, 3)'),
        M3ECardList(
          itemCount: 2,
          itemBuilder: (context, index) => _buildListItem(context, index + 2),
          onTap: (index) {},
          splashFactory: NoSplash.splashFactory,
          splashColor: Colors.transparent,
          highlightColor: Colors.transparent,
          margin: EdgeInsets.symmetric(horizontal: 20),
        ),
        const SizedBox(height: 24),

        _buildSectionHeader(context, 'Custom Splash (Data 4 - 8)'),
        M3ECardList(
          itemCount: 5,
          itemBuilder: (context, index) => _buildListItem(context, index + 4),
          splashColor: Colors.teal.withValues(alpha: 0.2),
          highlightColor: Colors.teal.withValues(alpha: 0.1),
          enableFeedback: true,
          onTap: (index) {},
          haptic: 2,
        ),
        const SizedBox(height: 24),

        _buildSectionHeader(context, 'Two Items (Data 9, 10)'),
        M3ECardList(
          itemCount: 2,
          itemBuilder: (context, index) => _buildListItem(context, index + 9),
          onTap: (index) {},
        ),
        const SizedBox(height: 24),

        _buildSectionHeader(context, 'Static Column (M3ECardColumn)'),
        M3ECardColumn(
          children: [
            _buildListItem(context, 11, onTap: false),
            _buildListItem(context, 12, onTap: false),
            _buildListItem(context, 13, onTap: false),
          ],
        ),
        const SizedBox(height: 24),
      ],
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return CustomScrollView(
      slivers: [
        SliverPadding(
          padding: const EdgeInsets.fromLTRB(16, 16, 16, 8),
          sliver: SliverToBoxAdapter(
            child: _buildSectionHeader(context, 'Single Item (Data 1)'),
          ),
        ),
        SliverPadding(
          padding: const EdgeInsets.symmetric(horizontal: 16.0),
          sliver: SliverM3ECardList(
            border: BorderSide(color: Theme.of(context).colorScheme.primary),
            elevation: 4,
            itemCount: 1,
            itemBuilder: (context, index) =>
                _buildListItem(context, 1, onTap: false),

            splashFactory: NoSplash.splashFactory,
            onTap: (index) {},
          ),
        ),

        const SliverToBoxAdapter(child: SizedBox(height: 16)),
        SliverPadding(
          padding: const EdgeInsets.fromLTRB(16, 8, 16, 8),
          sliver: SliverToBoxAdapter(
            child: _buildSectionHeader(context, 'Two Items (Data 2, 3)'),
          ),
        ),
        SliverPadding(
          padding: const EdgeInsets.symmetric(horizontal: 16.0),
          sliver: SliverM3ECardList(
            itemCount: 2,
            itemBuilder: (context, index) => _buildListItem(context, index + 2),
            onTap: (index) {},
          ),
        ),

        const SliverToBoxAdapter(child: SizedBox(height: 16)),
        SliverPadding(
          padding: const EdgeInsets.fromLTRB(16, 8, 16, 8),
          sliver: SliverToBoxAdapter(
            child: _buildSectionHeader(context, 'Custom Splash (Data 4 - 8)'),
          ),
        ),
        SliverPadding(
          padding: const EdgeInsets.symmetric(horizontal: 16.0),
          sliver: SliverM3ECardList(
            itemCount: 5,
            itemBuilder: (context, index) => _buildListItem(context, index + 4),
            splashColor: Colors.teal.withValues(alpha: 0.2),
            highlightColor: Colors.teal.withValues(alpha: 0.1),
            enableFeedback: true,
            onTap: (index) {},
          ),
        ),

        const SliverToBoxAdapter(child: SizedBox(height: 16)),
        SliverPadding(
          padding: const EdgeInsets.fromLTRB(16, 8, 16, 8),
          sliver: SliverToBoxAdapter(
            child: _buildSectionHeader(context, 'Two Items (Data 9, 10)'),
          ),
        ),
        SliverPadding(
          padding: const EdgeInsets.symmetric(horizontal: 16.0),
          sliver: SliverM3ECardList(
            itemCount: 2,
            itemBuilder: (context, index) => _buildListItem(context, index + 9),
            onTap: (index) {},
          ),
        ),

        const SliverPadding(padding: EdgeInsets.only(bottom: 32.0)),
      ],
    );
  }
}

Widget _buildSectionHeader(BuildContext context, String title) {
  return Padding(
    padding: const EdgeInsets.only(bottom: 8.0, left: 4.0),
    child: Text(
      title,
      style: TextStyle(
        fontWeight: FontWeight.bold,
        fontSize: 14,
        color: Theme.of(context).colorScheme.primary,
      ),
    ),
  );
}

Widget _buildListItem(BuildContext context, int number, {bool onTap = true}) {
  return Row(
    children: [
      Container(
        padding: const EdgeInsets.all(10),
        decoration: BoxDecoration(
          color: Theme.of(context).colorScheme.primary,
          borderRadius: BorderRadius.circular(12),
        ),
        child: Icon(
          Icons.library_books_outlined,
          color: Theme.of(context).colorScheme.onPrimary,
          size: 24,
        ),
      ),
      const SizedBox(width: 16),
      Expanded(
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          mainAxisSize: MainAxisSize.min,
          children: [
            Text(
              'Data $number',
              style: TextStyle(
                fontWeight: FontWeight.w600,
                fontSize: 16,
                color: Theme.of(context).colorScheme.onSurface,
              ),
            ),
            const SizedBox(height: 4),
            Text(
              'This is the subtitle for data item $number.',
              style: TextStyle(
                color: Theme.of(context).colorScheme.onSurfaceVariant,
                fontSize: 14,
              ),
            ),
          ],
        ),
      ),
      if (onTap) ...[
        Icon(
          Icons.chevron_right,
          color: Theme.of(
            context,
          ).colorScheme.onSurfaceVariant.withValues(alpha: 0.5),
        ),
      ],
    ],
  );
}
2
likes
160
points
91
downloads

Publisher

verified publishermuditpurohit.tech

Weekly Downloads

A Flutter package providing expressive Material 3 card lists with dynamically rounded corners for ListView, SliverList and Column.

Repository (GitHub)
View/report issues

Topics

#ui #material-3-expressive #m3e #listview #sliver

Documentation

API reference

License

MIT (license)

Dependencies

flutter

More

Packages that depend on m3e_card_list