Skip to content

主题系统

主题系统让你的 App 视觉风格统一,修改一处全局生效。Flutter 使用 ThemeDataColorScheme 来管理主题。

ThemeData 与 ColorScheme

全局主题配置

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(
      // ─── ★ 全局主题配置 ──────────────
      theme: ThemeData(
        // ─── ★ fromSeed 自动生成色彩方案 ──────────────
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.blue,
        ),
        // ─── ☆ fromSeed 自动生成色彩方案 ──────────────
        useMaterial3: true,
        fontFamily: 'NotoSansSC',
      ),
      // ─── ☆ 全局主题配置 ──────────────
      // ─── ★ 深色模式主题 ──────────────
      darkTheme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.blue,
          brightness: Brightness.dark,
        ),
      ),
      // ─── ☆ 深色模式主题 ──────────────
      // ─── ★ 跟随系统切换 ──────────────
      themeMode: ThemeMode.system,
      // ─── ☆ 跟随系统切换 ──────────────
      home: const Scaffold(body: Center(child: Text('主题示例'))),
    );
  }
}

ColorScheme — 色彩方案

ColorScheme 定义了一组协调的颜色,Material 3 推荐使用 fromSeed 自动生成:

dart
ColorScheme.fromSeed(seedColor: Colors.blue)

自动生成的颜色角色:

颜色角色用途
primary主色,按钮、重要元素
onPrimary主色上的文字颜色
primaryContainer主色容器(浅色背景)
onPrimaryContainer主色容器上的文字
secondary次要色
tertiary第三色
error错误色
surface页面背景色
onSurface页面文字色

手动定义 ColorScheme

注意

手动构造 ColorScheme 需要提供大量参数,容易遗漏。推荐使用 ColorScheme.fromSeed() 自动生成,只在有特殊需求时手动构造。

dart
ThemeData(
  colorScheme: ColorScheme(
    brightness: Brightness.light,
    primary: Color(0xFF2196F3),
    onPrimary: Colors.white,
    primaryContainer: Color(0xFFBBDEFB),
    onPrimaryContainer: Color(0xFF0D47A1),
    secondary: Color(0xFF03DAC6),
    onSecondary: Colors.black,
    secondaryContainer: Color(0xFFB2DFDB),
    onSecondaryContainer: Color(0xFF004D40),
    tertiary: Color(0xFF7C4DFF),
    onTertiary: Colors.white,
    error: Color(0xFFB00020),
    onError: Colors.white,
    surface: Colors.white,
    onSurface: Colors.black,
  ),
)

局部主题覆盖

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

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('局部主题覆盖')),
      body: Theme(
        data: Theme.of(context).copyWith(
          colorScheme: Theme.of(context).colorScheme.copyWith(
            primary: Colors.red,
          ),
        ),
        child: const Center(
          child: FilledButton(
            onPressed: null,
            child: Text('红色主题按钮'),
          ),
        ),
      ),
    );
  }
}

深色模式适配

方式一:跟随系统(推荐)

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

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
        useMaterial3: true,
      ),
      darkTheme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.blue,
          brightness: Brightness.dark,
        ),
        useMaterial3: true,
      ),
      themeMode: ThemeMode.system,
      home: const Scaffold(body: Center(child: Text('跟随系统深色模式'))),
    );
  }
}

方式二:手动切换

dart
class ThemeNotifier extends ChangeNotifier {
  ThemeMode _mode = ThemeMode.system;
  ThemeMode get mode => _mode;

  void toggle() {
    _mode = _mode == ThemeMode.light ? ThemeMode.dark : ThemeMode.light;
    notifyListeners();
  }
}

// 在 MaterialApp 中使用
Consumer<ThemeNotifier>(
  builder: (_, notifier, __) => MaterialApp(
    themeMode: notifier.mode,
    theme: lightTheme,
    darkTheme: darkTheme,
  ),
)

判断当前是否深色模式

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

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

  @override
  Widget build(BuildContext context) {
    final isDark = Theme.of(context).brightness == Brightness.dark;
    return Scaffold(
      body: Center(
        child: Text(isDark ? '当前是深色模式' : '当前是浅色模式'),
      ),
    );
  }
}

文字主题(TextTheme)

ThemeData.textTheme 定义了全局文字样式:

dart
ThemeData(
  textTheme: TextTheme(
    displayLarge: TextStyle(fontSize: 57, fontWeight: FontWeight.bold),
    headlineMedium: TextStyle(fontSize: 28, fontWeight: FontWeight.bold),
    titleLarge: TextStyle(fontSize: 22, fontWeight: FontWeight.bold),
    bodyLarge: TextStyle(fontSize: 16),
    bodyMedium: TextStyle(fontSize: 14),
    labelLarge: TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
  ),
)

使用主题文字样式:

dart
Text('标题', style: Theme.of(context).textTheme.titleLarge)
Text('正文', style: Theme.of(context).textTheme.bodyMedium)

主题速查

需求做法
设置全局主题MaterialApp(theme: ThemeData(...))
从一个颜色生成主题ColorScheme.fromSeed(seedColor: color)
深色模式同时设置 themedarkTheme
局部覆盖Theme(data: ..., child: ...)
获取当前主题Theme.of(context)
获取主题颜色Theme.of(context).colorScheme.primary
获取文字样式Theme.of(context).textTheme.bodyMedium

下一步

基于 Flutter 官方文档整理