material_design 0.30.0-dev copy "material_design: ^0.30.0-dev" to clipboard
material_design: ^0.30.0-dev copied to clipboard

The fastest path to consistent Material Design UIs in Flutter. Build beautiful apps aligned with official metrics and guidelines using a powerful set of ready-to-use design tokens and helper widgets.

Material Design 3 (2025) for Flutter #

pub version license Flutter Version style: very good analysis

The fastest path to consistent Material Design UIs in Flutter. Build beautiful apps aligned with official metrics and guidelines using a powerful set of ready-to-use design tokens and helper widgets.

This package provides a comprehensive toolkit for implementing Material Design 3 in Flutter. It includes a complete design token system and utilities that align with the official Material Design 3 specification, making it easier to build beautiful and consistent user interfaces.

🚀 Features #

  • Design Token System: A complete implementation of the Material Design 3 token hierarchy, including reference, system, and component tokens.
  • Adaptive Design: Utilities for creating adaptive layouts that respond to different screen sizes and platforms.
  • Material Design 3 Compliance: Built to align with the official Material Design 3 guidelines.

📦 Getting Started #

To use this package, add material_design as a dependency in your pubspec.yaml file.

dependencies:
  material_design: ^0.30.0-dev

Then, import the library in your Dart code:

import 'package:material_design/material_design.dart';

🎨 Usage #

Design Tokens #

The library provides a flexible system for defining and using design tokens.

// Create reference tokens
const primaryRef = ReferenceToken<Color>(
  Color(0xFF6750A4),
  'purple.40'
);

// Create system tokens
const primaryColor = SystemToken<Color>(
  Color(0xFF6750A4),
  'color.primary',
  referenceToken: primaryRef,
);

// Create component tokens
const buttonBackground = ComponentToken<Color>(
  Color(0xFF6750A4),
  'button.filled.background',
  systemToken: primaryColor,
  component: 'Button',
);

How to Use AdaptiveConfig #

Here is a basic example of how to use AdaptiveConfig within a Flutter widget. This StatelessWidget gets the screen dimensions and uses the configuration to display a different layout based on the current WindowSizeClass.

Example Code

import 'package.flutter/material.dart';
// Certifique-se de importar sua biblioteca. O caminho pode variar.
import 'package:your_project_name/material_adaptive.dart';

/// Uma tela que combina uma estrutura clara com lógica adaptativa avançada.
class BestResponsiveScreen extends StatelessWidget {
  const BestResponsiveScreen({super.key});

  @override
  Widget build(BuildContext context) {
    // 1. Obter a configuração adaptativa a partir do tamanho da tela.
    final Size screenSize = MediaQuery.of(context).size;
    final AdaptiveConfig config = AdaptiveConfig.fromDimensions(
      width: screenSize.width,
      height: screenSize.height,
    );

    // 2. Usar a estrutura limpa do 'switch' para lidar com os layouts.
    // Esta é a principal vantagem do segundo código: clareza e escalabilidade.
    switch (config.sizeClass) {
      case WindowSizeClass.compact:
        return _buildCompactLayout(config);
      case WindowSizeClass.medium:
        return _buildMediumLayout(config);
      case WindowSizeClass.expanded:
      case WindowSizeClass.large:
      case WindowSizeClass.extraLarge:
        // 3. Chamar um método de layout 'expanded' que agora possui a lógica
        // inteligente do primeiro código.
        return _buildSmartExpandedLayout(config);
    }
  }

  /// Layout para telas compactas: simples e direto.
  Widget _buildCompactLayout(AdaptiveConfig config) {
    return Scaffold(
      appBar: AppBar(title: const Text('Compact Layout')),
      body: Center(
        child: Text('Painel único para celular\nLargura: ${config.width.toInt()}px'),
      ),
      bottomNavigationBar: BottomNavigationBar(
        items: const [
          BottomNavigationBarItem(icon: Icon(Icons.article), label: 'Feed'),
          BottomNavigationBarItem(icon: Icon(Icons.chat), label: 'Chat'),
        ],
      ),
    );
  }

  /// Layout para telas médias: usa Navigation Rail para melhor uso do espaço.
  Widget _buildMediumLayout(AdaptiveConfig config) {
    return Scaffold(
      appBar: AppBar(title: const Text('Medium Layout')),
      body: Row(
        children: [
          NavigationRail(
            selectedIndex: 0,
            labelType: NavigationRailLabelType.all,
            destinations: const [
              NavigationRailDestination(icon: Icon(Icons.article), label: Text('Feed')),
              NavigationRailDestination(icon: Icon(Icons.chat), label: Text('Chat')),
            ],
          ),
          const VerticalDivider(thickness: 1, width: 1),
          Expanded(
            child: Center(
              child: Text(
                'Layout de dois painéis (List-Detail)\nLargura: ${config.width.toInt()}px',
              ),
            ),
          ),
        ],
      ),
    );
  }

  /// O "melhor dos dois mundos" para telas grandes.
  /// Usa a lógica detalhada do primeiro código dentro da estrutura limpa do segundo.
  Widget _buildSmartExpandedLayout(AdaptiveConfig config) {
    return Scaffold(
      body: Row(
        children: [
          // LÓGICA DO CÓDIGO 1: Escolhe dinamicamente entre Rail e Drawer.
          // Para telas 'Large' ou maiores, usa um Drawer permanente.
          // Para 'Expanded', pode usar um Rail para economizar espaço.
          if (AdaptiveUtils.shouldUsePermanentDrawer(config.sizeClass))
            NavigationDrawer(
              selectedIndex: 0,
              children: const [
                Padding(padding: EdgeInsets.all(28), child: Text('Header')),
                NavigationDrawerDestination(icon: Icon(Icons.article), label: Text('Feed')),
                NavigationDrawerDestination(icon: Icon(Icons.chat), label: Text('Chat')),
              ],
            )
          else
            NavigationRail(
              selectedIndex: 0,
              labelType: NavigationRailLabelType.all,
              destinations: const [
                NavigationRailDestination(icon: Icon(Icons.article), label: Text('Feed')),
                NavigationRailDestination(icon: Icon(Icons.chat), label: Text('Chat')),
              ],
            ),
          const VerticalDivider(thickness: 1, width: 1),

          // LÓGICA DO CÓDIGO 1: Centraliza e limita a largura do conteúdo principal
          // para melhor legibilidade em telas muito largas.
          Expanded(
            child: Center(
              child: ConstrainedBox(
                constraints: BoxConstraints(maxWidth: config.maxContentWidth),
                child: Container(
                  color: Colors.blue.shade50,
                  child: Center(
                    child: Text(
                      'Conteúdo Principal\n(Largura máxima: ${config.maxContentWidth.toInt()}px)',
                      textAlign: TextAlign.center,
                    ),
                  ),
                ),
              ),
            ),
          ),

          // LÓGICA DO CÓDIGO 1: Adiciona um painel de apoio (terceiro painel)
          // apenas se houver espaço suficiente (telas Large/ExtraLarge).
          if (config.supportsThreePane) ...[
            const VerticalDivider(thickness: 1, width: 1),
            SizedBox(
              width: AdaptiveUtils.getSupportingPaneWidth(
                totalWidth: config.width,
                sizeClass: config.sizeClass,
              ),
              child: Container(
                color: Colors.green.shade50,
                child: const Center(child: Text('Painel de Apoio')),
              ),
            ),
          ]
        ],
      ),
    );
  }
}

// Stubs para os widgets de navegação para o código compilar.
// No seu projeto real, você usaria seus próprios widgets.
class NavigationDrawer extends StatelessWidget {
  final int selectedIndex;
  final List<Widget> children;
  const NavigationDrawer({super.key, required this.selectedIndex, required this.children});
  @override
  Widget build(BuildContext context) => SizedBox(width: 250, child: Column(children: children));
}

🙏 Contributing #

Contributions are welcome! Please see the CONTRIBUTING.md file for more information.

📄 License #

This project is licensed under the MIT License - see the LICENSE file for details.

23
likes
0
points
787
downloads

Publisher

unverified uploader

Weekly Downloads

The fastest path to consistent Material Design UIs in Flutter. Build beautiful apps aligned with official metrics and guidelines using a powerful set of ready-to-use design tokens and helper widgets.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter, meta, vector_math

More

Packages that depend on material_design