Flutter Material 3设计语言详解

在 Flutter 中,Material 3(也称为 Material You)是 Google 最新的设计语言,它在 Material 2 的基础上进行了重大升级,提供了更个性化、更现代的设计体验。

Material 3 的主要特性

1. 动态色彩 (Dynamic Color)

Material 3 的核心特性之一是从用户壁纸中提取颜色主题。

Dart 复制代码
import 'package:flutter/material.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Material 3 Demo',
      theme: ThemeData(
        useMaterial3: true, // 启用 Material 3
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.deepPurple, // 从种子颜色生成完整配色
        ),
      ),
      home: const MyHomePage(),
    );
  }
}

2. 更新的组件样式

按钮 (Buttons)
Dart 复制代码
class ButtonExamples extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        FilledButton(
          onPressed: () {},
          child: const Text('Filled Button'),
        ),
        const SizedBox(height: 10),
        FilledButton.tonal(
          onPressed: () {},
          child: const Text('Tonal Button'),
        ),
        const SizedBox(height: 10),
        OutlinedButton(
          onPressed: () {},
          child: const Text('Outlined Button'),
        ),
        const SizedBox(height: 10),
        TextButton(
          onPressed: () {},
          child: const Text('Text Button'),
        ),
      ],
    );
  }
}
导航栏 (Navigation Bar)
Dart 复制代码
class BottomNavigationExample extends StatefulWidget {
  const BottomNavigationExample({super.key});

  @override
  State<BottomNavigationExample> createState() =>
      _BottomNavigationExampleState();
}

class _BottomNavigationExampleState extends State<BottomNavigationExample> {
  int _selectedIndex = 0;

  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Material 3 Navigation'),
      ),
      body: Center(
        child: Text('Selected Page: $_selectedIndex'),
      ),
      bottomNavigationBar: NavigationBar(
        selectedIndex: _selectedIndex,
        onDestinationSelected: _onItemTapped,
        destinations: const [
          NavigationDestination(
            icon: Icon(Icons.home),
            label: 'Home',
          ),
          NavigationDestination(
            icon: Icon(Icons.business),
            label: 'Business',
          ),
          NavigationDestination(
            icon: Icon(Icons.school),
            label: 'School',
          ),
        ],
      ),
    );
  }
}

3. 完整的 Material 3 主题配置

Dart 复制代码
ThemeData getMaterial3Theme(bool isDark) {
  return ThemeData(
    useMaterial3: true,
    colorScheme: isDark 
      ? ColorScheme.dark(
          primary: Colors.blue,
          secondary: Colors.cyan,
          background: Colors.grey[900]!,
        )
      : ColorScheme.light(
          primary: Colors.blue,
          secondary: Colors.cyan,
          background: Colors.white,
        ),
    // 或者使用 fromSeed 自动生成
    // colorScheme: ColorScheme.fromSeed(
    //   seedColor: Colors.blue,
    //   brightness: isDark ? Brightness.dark : Brightness.light,
    // ),
    
    // 文字主题
    textTheme: TextTheme(
      displayLarge: TextStyle(
        fontSize: 57,
        fontWeight: FontWeight.w400,
        color: isDark ? Colors.white : Colors.black87,
      ),
      titleLarge: TextStyle(
        fontSize: 22,
        fontWeight: FontWeight.w400,
        color: isDark ? Colors.white : Colors.black87,
      ),
      bodyLarge: TextStyle(
        fontSize: 16,
        fontWeight: FontWeight.w400,
        color: isDark ? Colors.white70 : Colors.black54,
      ),
    ),
    
    // 组件主题
    cardTheme: CardTheme(
      elevation: 1,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(12),
      ),
    ),
    
    elevatedButtonTheme: ElevatedButtonThemeData(
      style: ElevatedButton.styleFrom(
        padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(20),
        ),
      ),
    ),
  );
}

4. 响应式设计改进

Dart 复制代码
class AdaptiveLayoutExample extends StatelessWidget {
  const AdaptiveLayoutExample({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Adaptive Layout'),
      ),
      body: CustomScrollView(
        slivers: [
          // 大屏幕顶部的应用栏
          SliverAppBar.large(
            title: const Text('Large App Bar'),
          ),
          // 中等屏幕应用栏
          SliverAppBar.medium(
            title: const Text('Medium App Bar'),
          ),
          // 常规应用栏
          SliverAppBar(
            title: const Text('Regular App Bar'),
          ),
          // 内容区域
          SliverList(
            delegate: SliverChildBuilderDelegate(
              (context, index) => ListTile(
                leading: Icon(
                  Icons.circle,
                  color: Theme.of(context).colorScheme.primary,
                ),
                title: Text('Item $index'),
                subtitle: Text('Subtitle for item $index'),
                trailing: IconButton(
                  icon: const Icon(Icons.more_vert),
                  onPressed: () {},
                ),
              ),
              childCount: 20,
            ),
          ),
        ],
      ),
    );
  }
}

启用 Material 3 的步骤

  1. 在 ThemeData 中设置 useMaterial3
Dart 复制代码
MaterialApp(
  theme: ThemeData(useMaterial3: true),
)
  1. 配置颜色方案
Dart 复制代码
// 方法1: 从种子颜色生成
colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue)

// 方法2: 自定义完整配色
colorScheme: ColorScheme(
  primary: Colors.blue,
  secondary: Colors.cyan,
  // ... 其他颜色
)
  1. 更新组件使用新的 Widget

    • 使用 NavigationBar 替代 BottomNavigationBar

    • 使用 FilledButton 替代已弃用的按钮变体

    • 使用 SegmentedButton 进行分段选择

相关推荐
zzzzzz3101 小时前
看 react-bits,不要只看“酷炫”:一套阅读动画交互组件库的框架
javascript·react.js·动效
香芋芋圆9 小时前
AI 冲击内卷之下,普通前端如何破局?WebGIS—— 低门槛突围赛道
前端·javascript·人工智能·学习·职场发展
INS_KF9 小时前
【编程笔记】成员函数中两个 const 的区别(const Data &getData() const;)
前端·javascript·笔记
宿67410 小时前
vue3-async
前端·javascript·vue.js
excel11 小时前
Nuxt + Twin CSS 中宽度超过屏幕时底部出现空白的原因与解决方案
前端·javascript
一个游离的指针14 小时前
函数管道:消除深度嵌套调用
前端·javascript
柚yuzumi14 小时前
前端优化,从少触发一次开始:防抖与节流
前端·javascript
默_笙15 小时前
🚤 CSS 布局的"圈地运动":BFC 就是浏览器的独立领地
前端·javascript
用户9385156350715 小时前
大模型记忆指南:从短时缓存到永久记忆,手把手带你吃透 LangChain Memory 管理
javascript·人工智能
末代iOS程序员华仔15 小时前
iOS 5.6 条例解决方法
flutter·ios·swift