Flutter主题配置插件theme_config的使用

Flutter主题配置插件theme_config的使用

ThemeConfig 使得在平台主题改变时切换状态栏和导航栏样式变得简单。

主题模式 覆盖样式 自定义覆盖样式 页面覆盖样式

特性

  • 设置系统栏的亮色和暗色样式
  • 自动更新系统栏当平台亮度变化时
  • 监听主题模式变化

开始使用

创建一个独立定义每个样式的主题配置文件:

final themeProfile = ThemeProfile(
  theme: ThemeData.light(),
  darkTheme: ThemeData.dark(),
  overlayStyle: SystemUiOverlayStyle.light,
  darkOverlayStyle: SystemUiOverlayStyle.dark,
);

或者基于颜色方案:

final themeProfile = ThemeProfile.fromColorScheme(
  colorScheme: ColorScheme.light(),
  darkColorScheme: ColorScheme.dark(),
  theme: (colorScheme) => ThemeData.from(colorScheme: colorScheme),
  overlayStyle: (colorScheme) => SystemUiOverlayStyle(
    statusBarColor: Colors.transparent,
    statusBarIconBrightness: Brightness.light,
    systemNavigationBarColor: Colors.black,
    systemNavigationBarIconBrightness: Brightness.light,
  ),
);

初始化 ThemeConfig 以便它可以保存和加载主题模式偏好设置:

Future<void> main() async {
  ...
  await ThemeConfig.init(themeProfile);
  runApp(MyApp());
}

MaterialApp 包裹在 ThemeBuilder 中,以便它可以监听平台亮度和主题模式的变化并相应地更改系统栏:

ThemeBuilder(
  builder: (theme) => MaterialApp(
    ...
    theme: theme.light,
    darkTheme: theme.dark,
    themeMode: theme.mode,
  ),
)

使用方法

在项目的任何位置访问应用程序的亮度和主题模式:

final brightness = ThemeConfig.brightness;
final themeMode = ThemeConfig.themeMode;

在不同主题模式之间切换:

ThemeConfig.setThemeMode(ThemeMode.light);
ThemeConfig.setThemeMode(ThemeMode.dark);
ThemeConfig.setThemeMode(ThemeMode.system);

例如使用 RadioListTile

Widget myRadioListTile(ThemeMode themeMode) {
  return RadioListTile<ThemeMode>(
    title: Text(themeMode.name),
    value: themeMode,
    groupValue: ThemeConfig.themeMode,
    onChanged: (mode) => setState(() => ThemeConfig.setThemeMode(mode)),
  );
}
Column(children: ThemeMode.values.map(myRadioListTile).toList())

动态重新定义覆盖样式:

ThemeConfig.setOverlayStyle(newOverlayStyle);
ThemeConfig.setDarkOverlayStyle(newDarkOverlayStyle);

更改当前覆盖样式:

ThemeConfig.setCustomOverlayStyle(customOverlayStyle);

移除当前覆盖样式:

ThemeConfig.removeCustomOverlayStyle();

临时更改特定页面上的亮色和/或暗色覆盖样式:

OverlayStyle(
  light: newOverlayStyle,
  dark: newDarkOverlayStyle,
  child: ...
)

或者使用自定义覆盖样式:

OverlayStyle.custom(
  style: customOverlayStyle,
  child: ...
)

为了让此组件工作,你还需要将我们的观察者添加到 MaterialApp

MaterialApp(
  ...
  navigatorObservers: [ThemeConfig.routeObserver],
)

其他信息

如果您发现任何不在 issues 中的错误,请提交一个新的问题。如果您愿意自己修复或增强某些功能,欢迎提交拉取请求。


完整示例代码

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

// 1. 创建一个主题配置文件
final themeProfile = ThemeProfile.fromColorScheme(
  // 定义颜色方案
  colorScheme: const ColorScheme.light(),
  darkColorScheme: const ColorScheme.dark(),
  // 定义主题
  theme: (colorScheme) => ThemeData(
    colorScheme: colorScheme,
    scaffoldBackgroundColor: colorScheme.background,
    appBarTheme: AppBarTheme(
      elevation: 0,
      color: colorScheme.background,
      foregroundColor: colorScheme.onBackground,
    ),
  ),
  // 定义覆盖样式
  overlayStyle: (colorScheme) => SystemUiOverlayStyle(
    // android
    statusBarColor: Colors.transparent,
    statusBarIconBrightness: colorScheme.brightness == Brightness.light ? Brightness.dark : Brightness.light,
    systemNavigationBarColor: colorScheme.background,
    systemNavigationBarIconBrightness: colorScheme.brightness == Brightness.light ? Brightness.dark : Brightness.light,
    // ios
    statusBarBrightness: colorScheme.brightness,
  ),
);

void main() async {
  // 2. 初始化插件
  await ThemeConfig.init(themeProfile);
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    // 3. 将应用包裹在 ThemeBuilder 中
    // 监听主题和亮度变化
    return ThemeBuilder(
      builder: (theme) {
        return MaterialApp(
          debugShowCheckedModeBanner: false,
          title: 'ThemeConfig 示例',
          home: const Example(),
          // 4. 设置主题属性
          theme: theme.light,
          darkTheme: theme.dark,
          themeMode: theme.mode,
          // 如果计划使用 OverlayStyle 组件,请添加此行
          navigatorObservers: [ThemeConfig.routeObserver],
        );
      },
    );
  }
}

class Example extends StatefulWidget {
  const Example({Key? key}) : super(key: key);

  [@override](/user/override)
  State<Example> createState() => _ExampleState();
}

class _ExampleState extends State<Example> {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('ThemeConfig 示例')),
      body: SingleChildScrollView(
        child: Column(
          children: [
            ...ThemeMode.values.map(
              (themeMode) => radioTile(themeMode, setState),
            ),
            const SizedBox(height: 16),
            OutlinedButton(
              child: const Text('设置亮色覆盖样式'),
              onPressed: () => ThemeConfig.setOverlayStyle(
                const SystemUiOverlayStyle(
                  statusBarColor: Colors.yellow,
                  systemNavigationBarColor: Colors.yellow,
                ),
              ),
            ),
            OutlinedButton(
              child: const Text('设置暗色覆盖样式'),
              onPressed: () => ThemeConfig.setDarkOverlayStyle(
                const SystemUiOverlayStyle(
                  statusBarColor: Colors.deepPurple,
                  systemNavigationBarColor: Colors.deepPurple,
                ),
              ),
            ),
            const SizedBox(height: 16),
            OutlinedButton(
              child: const Text('设置自定义覆盖样式'),
              onPressed: () => ThemeConfig.setCustomOverlayStyle(
                const SystemUiOverlayStyle(
                  statusBarColor: Colors.pink,
                  systemNavigationBarColor: Colors.pink,
                ),
              ),
            ),
            OutlinedButton(
              child: const Text('移除自定义覆盖样式'),
              onPressed: () => ThemeConfig.removeCustomOverlayStyle(),
            ),
            const SizedBox(height: 16),
            OutlinedButton(
              child: const Text('导航到亮色/暗色覆盖页面'),
              onPressed: () => Navigator.push(
                context,
                MaterialPageRoute(builder: (_) => const OverlayPage()),
              ).then((_) => setState(() {})),
            ),
            OutlinedButton(
              child: const Text('导航到自定义覆盖页面'),
              onPressed: () => Navigator.push(
                context,
                MaterialPageRoute(builder: (_) => const CustomOverlayPage()),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class OverlayPage extends StatefulWidget {
  const OverlayPage({Key? key}) : super(key: key);

  [@override](/user/override)
  State<OverlayPage> createState() => _OverlayPageState();
}

class _OverlayPageState extends State<OverlayPage> {
  [@override](/user/override)
  Widget build(BuildContext context) {
    return OverlayStyle(
      light: const SystemUiOverlayStyle(
        statusBarColor: Colors.orange,
        systemNavigationBarColor: Colors.orange,
      ),
      dark: const SystemUiOverlayStyle(
        statusBarColor: Colors.blue,
        systemNavigationBarColor: Colors.blue,
      ),
      child: Scaffold(
        body: SafeArea(
          child: SingleChildScrollView(
            child: Column(
              children: [
                ...ThemeMode.values.map(
                  (themeMode) => radioTile(themeMode, setState),
                ),
                OutlinedButton(
                  child: const Text('返回'),
                  onPressed: Navigator.of(context).pop,
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

class CustomOverlayPage extends StatelessWidget {
  const CustomOverlayPage({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return OverlayStyle.custom(
      style: const SystemUiOverlayStyle(
        statusBarColor: Colors.green,
        systemNavigationBarColor: Colors.green,
      ),
      child: Scaffold(
        body: Center(
          child: OutlinedButton(
            child: const Text('返回'),
            onPressed: Navigator.of(context).pop,
          ),
        ),
      ),
    );
  }
}

Widget radioTile(
  ThemeMode themeMode,
  void Function(void Function()) setState,
) =>
    RadioListTile<ThemeMode>(
      title: Text(themeMode.name),
      value: themeMode,
      groupValue: ThemeConfig.themeMode,
      onChanged: (mode) => setState(() => ThemeConfig.setThemeMode(mode!)),
    );

更多关于Flutter主题配置插件theme_config的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html

1 回复

更多关于Flutter主题配置插件theme_config的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,以下是如何在Flutter项目中使用theme_config插件来配置主题的一个基本示例。theme_config插件允许你动态地更改应用的主题,包括颜色、字体等。不过,需要注意的是,theme_config并非Flutter官方插件,所以具体的使用方式可能会根据插件的版本和文档有所不同。这里我们假设插件的使用方式与常见的主题管理插件类似。

首先,你需要在你的pubspec.yaml文件中添加theme_config插件(注意:这里假设插件名为theme_config,如果实际插件名称不同,请替换为实际名称):

dependencies:
  flutter:
    sdk: flutter
  theme_config: ^x.y.z  # 替换为实际的版本号

然后运行flutter pub get来安装插件。

接下来,我们设置应用的主题。在lib目录下创建一个新的Dart文件,比如theme_data.dart,用于定义我们的主题数据:

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

final LightTheme = ThemeData(
  primarySwatch: Colors.blue,
  visualDensity: VisualDensity.adaptivePlatformDensity,
);

final DarkTheme = ThemeData(
  brightness: Brightness.dark,
  primarySwatch: Colors.blueGrey,
  visualDensity: VisualDensity.adaptivePlatformDensity,
);

然后,在你的main.dart文件中,使用theme_config插件来管理主题:

// main.dart
import 'package:flutter/material.dart';
import 'package:theme_config/theme_config.dart';  // 假设插件提供这样的导入路径
import 'theme_data.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ThemeConfig(
      initialTheme: LightTheme,  // 设置初始主题
      themes: {
        'light': LightTheme,
        'dark': DarkTheme,
      },
      builder: (context, theme) {
        return MaterialApp(
          title: 'Flutter Theme Config Demo',
          theme: theme,
          home: HomeScreen(),
        );
      },
    );
  }
}

class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  @override
  Widget build(BuildContext context) {
    final ThemeConfig themeConfig = ThemeConfig.of(context);

    return Scaffold(
      appBar: AppBar(
        title: Text('Theme Config Demo'),
        actions: [
          IconButton(
            icon: Icon(themeConfig.currentThemeName == 'light' ? Icons.dark_mode : Icons.light_mode),
            onPressed: () {
              setState(() {
                themeConfig.setThemeName(themeConfig.currentThemeName == 'light' ? 'dark' : 'light');
              });
            },
          ),
        ],
      ),
      body: Center(
        child: Text('Current Theme: ${themeConfig.currentThemeName}'),
      ),
    );
  }
}

在这个示例中,我们做了以下几件事:

  1. theme_data.dart中定义了两个主题:LightThemeDarkTheme
  2. main.dart中使用ThemeConfig包装了MaterialApp,并设置了初始主题和可用的主题。
  3. HomeScreen中,通过ThemeConfig.of(context)获取当前的ThemeConfig实例,并在AppBar中添加了一个按钮来切换主题。

请注意,上述代码是基于假设的theme_config插件的使用方式。实际使用时,请查阅该插件的官方文档以获取准确的API和用法。如果theme_config插件不存在或API有所不同,你可能需要寻找其他类似功能的插件或手动实现主题管理功能。

回到顶部