Flutter动态主题切换插件dynamik_theme的使用

发布于 1周前 作者 phonegap100 来自 Flutter

Flutter动态主题切换插件dynamik_theme的使用

插件简介

dynamik_theme 是一个Flutter插件,它可以帮助你轻松设置主题模式或自定义颜色。该插件支持在支持的平台上使用动态颜色,并且可以通过你选择的存储方式持久化主题状态。

dynamik_theme Banner

主要功能

  • Light Mode:基于浅色方案的主题。
  • Dark Mode:基于深色方案的主题。
  • System Mode:根据系统设置自动切换浅色或深色主题。
  • Dynamic Color:使用 dynamic_color 从设备中自动获取颜色(不支持iOS)。
  • Custom Color:设置任何你想要的颜色。

dynamik_theme 动态演示

使用方法

1. 设置存储

为了持久化主题状态,你需要实现 ThemeStorage 接口。以下是一个使用 Hive 作为存储的示例:

class HiveStorage extends ThemeStorage {
  final box = Hive.box<String>(_boxName);
  final key = 'theme';

  @override
  Future<void> delete() async {
    await box.clear();
  }

  @override
  ThemeState? read() {
    final res = box.get(key);
    if (res == null) return null;
    return ThemeState.fromJson(res);
  }

  @override
  Future<void> write(ThemeState state) async {
    await box.put(key, state.toJson());
  }
}

你也可以使用 SharedPreferences 或其他数据库来实现 ThemeStorage

main.dart 中初始化存储:

void main() async {
  // 初始化 Hive
  await Hive.initFlutter();
  await Hive.openBox<String>(_boxName);

  // 设置 ThemeStorage。如果不设置,默认使用 InMemoryThemeStorage。
  ThemeConfig.storage = HiveStorage();

  runApp(const MyApp());
}

2. 使用 DynamikTheme

MyApp 中使用 DynamikTheme 来配置主题:

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

  @override
  Widget build(BuildContext context) {
    return DynamikTheme(
      config: ThemeConfig(
        useMaterial3: true,
        // 你可以从 https://m3.material.io/theme-builder#/custom 生成颜色方案
        lightScheme: ColorScheme.fromSeed(seedColor: Colors.red),
        darkScheme: ColorScheme.fromSeed(
          seedColor: Colors.red,
          brightness: Brightness.dark,
        ),
        defaultThemeState: SimpleThemeType.dynamik.themeState,
        builder: (themeData) {
          // 添加更多自定义配置
          return themeData.copyWith(
            appBarTheme: const AppBarTheme(centerTitle: true),
            inputDecorationTheme: const InputDecorationTheme(
              border: OutlineInputBorder(),
            ),
          );
        },
      ),
      builder: (theme, darkTheme, themeMode) {
        return MaterialApp(
          themeMode: themeMode,
          theme: theme,
          darkTheme: darkTheme,
          debugShowCheckedModeBanner: false,
          home: const Home(),
        );
      },
    );
  }
}

3. 更新主题

你可以通过以下方式更新主题:

  • 设置新的主题

    DynamikTheme.of(context).setTheme(themeState);
    
  • 更改主题模式

    DynamikTheme.of(context).setThemeMode(ThemeMode.light);  // 或 ThemeMode.dark, ThemeMode.system
    
  • 设置动态颜色模式

    DynamikTheme.of(context).setDynamikColorMode();  // 自动从设备获取颜色(不支持iOS)
    
  • 设置自定义颜色

    DynamikTheme.of(context).setCustomColorMode(color);
    

4. 示例代码

以下是一个完整的示例代码,展示了如何使用 dynamik_theme 插件来实现动态主题切换:

import 'dart:math';
import 'package:dynamik_theme/dynamik_theme.dart';
import 'package:flutter/material.dart';
import 'package:hive_flutter/adapters.dart';

const _boxName = 'theme-storage';
const _space = SizedBox(height: 16, width: 16);
final _colors = List.generate(
  8,
  (index) => Color((Random().nextDouble() * 0xFFFFFF).toInt()).withOpacity(1.0),
);

class HiveStorage extends ThemeStorage {
  final box = Hive.box<String>(_boxName);
  final key = 'theme';

  @override
  Future<void> delete() async {
    await box.clear();
  }

  @override
  ThemeState? read() {
    final res = box.get(key);
    if (res == null) return null;
    return ThemeState.fromJson(res);
  }

  @override
  Future<void> write(ThemeState state) async {
    await box.put(key, state.toJson());
  }
}

void main() async {
  await Hive.initFlutter();
  await Hive.openBox<String>(_boxName);

  /// 设置 ThemeStorage。如果不设置,默认使用 InMemoryThemeStorage。
  ThemeConfig.storage = HiveStorage();
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return DynamikTheme(
      config: ThemeConfig(
        useMaterial3: true,
        // 你可以从 https://m3.material.io/theme-builder#/custom 生成颜色方案
        lightScheme: ColorScheme.fromSeed(seedColor: Colors.red),
        darkScheme: ColorScheme.fromSeed(
          seedColor: Colors.red,
          brightness: Brightness.dark,
        ),
        defaultThemeState: SimpleThemeType.dynamik.themeState,
        builder: (themeData) {
          return themeData.copyWith(
            appBarTheme: const AppBarTheme(centerTitle: true),
            inputDecorationTheme: const InputDecorationTheme(
              border: OutlineInputBorder(),
            ),
          );
        },
      ),
      builder: (theme, darkTheme, themeMode) {
        return MaterialApp(
          themeMode: themeMode,
          theme: theme,
          darkTheme: darkTheme,
          debugShowCheckedModeBanner: false,
          home: const Home(),
        );
      },
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    final themeState = DynamikTheme.of(context).themeState;

    return Scaffold(
      appBar: AppBar(
        title: const Text('Dynamik Theme'),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {},
        child: const Icon(Icons.create),
      ),
      body: SingleChildScrollView(
        padding: const EdgeInsets.all(8),
        child: Column(
          children: [
            Center(
              child: Text(
                'SimpleThemeType:',
                style: Theme.of(context).textTheme.titleMedium,
              ),
            ),
            _space,
            Wrap(
              runSpacing: 10,
              spacing: 10,
              children: SimpleThemeType.values
                  .map((e) => InputChip(
                        label: Text(e.name),
                        selected: themeState == e.themeState,
                        onPressed: () {
                          DynamikTheme.of(context).setTheme(e.themeState);
                        },
                      ))
                  .toList(),
            ),
            _space,
            _space,
            Text(
              'Custom Colors:',
              style: Theme.of(context).textTheme.titleMedium,
            ),
            _space,
            Wrap(
              runSpacing: 10,
              spacing: 10,
              children: ThemeMode.values
                  .map(
                    (e) => InputChip(
                      label: Text(e.name),
                      selected: themeState.themeMode == e,
                      onPressed: () {
                        DynamikTheme.of(context).setThemeMode(e);
                      },
                    ),
                  )
                  .toList(),
            ),
            _space,
            Wrap(
              runSpacing: 10,
              spacing: 10,
              children: ColorMode.values
                  .map(
                    (e) => InputChip(
                      label: Text(e.name),
                      selected: themeState.colorMode == e,
                      onPressed: e == ColorMode.dynamik
                          ? () {
                              DynamikTheme.of(context).setDynamikColorMode();
                            }
                          : null,
                    ),
                  )
                  .toList(),
            ),
            _space,
            Wrap(
              spacing: 10,
              runSpacing: 10,
              key: const ValueKey('value'),
              children: _colors.map((e) {
                return GestureDetector(
                  onTap: () {
                    DynamikTheme.of(context).setCustomColorMode(e);
                  },
                  child: CircleAvatar(
                    backgroundColor: e,
                  ),
                );
              }).toList(),
            ),
            _space,
            const Divider(),
            _space,
            Wrap(
              runSpacing: 10,
              spacing: 10,
              children: [
                TextButton(onPressed: () {}, child: const Text('TextButton')),
                ElevatedButton.icon(
                  onPressed: () {},
                  icon: const Icon(Icons.image),
                  label: const Text('ElevatedButton'),
                ),
                FilledButton(
                  onPressed: () {},
                  child: const Text('FilledButton'),
                ),
              ],
            ),
            _space,
            const TextField(),
            _space,
            const TextField(
              decoration: InputDecoration(
                border: UnderlineInputBorder(),
                errorText: 'ErrorText',
              ),
            ),
            _space,
            CheckboxListTile(
              title: const Text('CheckboxListTile'),
              value: true,
              onChanged: (_) {},
            ),
            RadioListTile(
              value: true,
              groupValue: true,
              onChanged: (_) {},
              title: const Text('RadioListTile'),
            ),
          ],
        ),
      ),
    );
  }
}

5. 预定义的主题状态列表

你可以使用 SimpleThemeType 提供的预定义主题状态,或者创建自己的主题状态列表:

enum MyThemeType {
  dynamik(ThemeState(
    themeMode: ThemeMode.system,
    colorMode: ColorMode.dynamik,
  )),
  light(ThemeState(themeMode: ThemeMode.light)),
  dark(ThemeState(themeMode: ThemeMode.dark));

  const MyThemeType(this.themeState);
  final ThemeState themeState;
}

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

1 回复

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


当然,下面是一个关于如何使用Flutter动态主题切换插件dynamik_theme的示例代码。这个示例将展示如何集成dynamik_theme插件并实现简单的主题切换功能。

1. 添加依赖

首先,在你的pubspec.yaml文件中添加dynamik_theme的依赖:

dependencies:
  flutter:
    sdk: flutter
  dynamik_theme: ^latest_version  # 请替换为实际的最新版本号

2. 导入插件并配置主题

在你的main.dart文件中,导入dynamik_theme并配置主题。

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return DynamikTheme(
      defaultThemeMode: ThemeMode.system, // 可以设置为 ThemeMode.light 或 ThemeMode.dark
      themes: {
        ThemeMode.light: lightTheme(),
        ThemeMode.dark: darkTheme(),
      },
      child: MaterialApp(
        title: 'Dynamik Theme Example',
        themeMode: DynamikTheme.of(context).themeMode, // 使用 DynamikTheme 的 themeMode
        theme: DynamikTheme.of(context).theme, // 使用 DynamikTheme 的 theme
        darkTheme: DynamikTheme.of(context).darkTheme, // 使用 DynamikTheme 的 darkTheme
        home: HomeScreen(),
      ),
    );
  }

  // 定义 Light 主题
  ThemeData lightTheme() {
    return ThemeData(
      brightness: Brightness.light,
      primarySwatch: Colors.blue,
      // 其他主题配置
    );
  }

  // 定义 Dark 主题
  ThemeData darkTheme() {
    return ThemeData(
      brightness: Brightness.dark,
      primarySwatch: Colors.blueGrey,
      // 其他主题配置
    );
  }
}

3. 创建切换主题的按钮

在你的HomeScreen中,创建一个按钮来切换主题。

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

class _HomeScreenState extends State<HomeScreen> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Dynamik Theme Example'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Current Theme Mode: ${DynamikTheme.of(context).themeMode.toString()}',
              style: TextStyle(fontSize: 20),
            ),
            SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                setState(() {
                  DynamikTheme.of(context).setThemeMode(
                    DynamikTheme.of(context).themeMode == ThemeMode.light
                        ? ThemeMode.dark
                        : ThemeMode.light,
                  );
                });
              },
              child: Text('Switch Theme'),
            ),
          ],
        ),
      ),
    );
  }
}

4. 运行应用

现在,你可以运行你的Flutter应用,应该能够看到一个按钮,点击该按钮可以在Light和Dark主题之间切换。

注意事项

  • 确保你已经正确安装了Flutter和Dart环境。
  • 插件的版本号可能会更新,请确保使用最新版本。
  • 你可以根据需要进一步自定义主题,包括颜色、字体等。

以上示例展示了如何使用dynamik_theme插件在Flutter应用中实现动态主题切换功能。希望这对你有所帮助!

回到顶部