Flutter主题扩展插件extended_theme的使用

Flutter主题扩展插件extended_theme的使用

extended_theme 是一个用于简化Flutter应用程序中主题管理的插件。它允许你创建主题集、扩展标准主题,并在运行时更新主题。你可以定义自己的主题类,或者直接使用Material和Cupertino主题。

使用方法

1. 定义主题类(可选)

你可以通过继承 ExtendedTheme 类来定义自己的主题类。如果你不需要自定义属性,可以直接使用 ExtendedTheme 类。记得在构造函数中调用父类的构造函数,并传递 materialcupertino 主题数据。

class AppTheme extends ExtendedTheme {
  final Color? shadowColor;
  final Color? buttonPauseColor;
  final Color? subtitleColor;
  final double? centerFontSize;

  AppTheme(ThemeData material,
      {this.shadowColor,
      this.buttonPauseColor,
      this.subtitleColor,
      this.centerFontSize})
      : super(material: material);
}
2. 定义主题配置(预定义主题)

你可以为应用程序定义多个主题,并将它们存储在一个映射中。每个主题可以有不同的颜色、字体大小等属性。

const MagentaLight = 'MagentaLight';
const MagentaDark = 'MagentaDark';
const GreenLight = 'GreenLight';
const GreenDark = 'GreenDark';
const BlueLight = 'BlueLight';
const BlueDark = 'BlueDark';

final appThemes = {
  MagentaLight: AppTheme(
      ThemeData.light().copyWith(primaryColor: const Color(0xffcc0066)),
      subtitleColor: const Color(0xff8e8e8e),
      centerFontSize: 28),

  MagentaDark: AppTheme(
      ThemeData.dark().copyWith(primaryColor: const Color(0xffcc0066)),
      subtitleColor: const Color(0xffA5A5A5),
      centerFontSize: 14),

  GreenLight: AppTheme(ThemeData.light().copyWith(primaryColor: Colors.green),
      subtitleColor: const Color(0xff8e8e8e), centerFontSize: 22),

  GreenDark: AppTheme(ThemeData.dark().copyWith(primaryColor: Colors.green[700]),
      subtitleColor: const Color(0xffA5A5A5), centerFontSize: 12),

  BlueLight: AppTheme(ThemeData.light().copyWith(primaryColor: Colors.blue),
      subtitleColor: const Color(0xff8e8e8e), centerFontSize: 14),

  BlueDark: AppTheme(ThemeData.dark().copyWith(primaryColor: Colors.blue[700]),
      subtitleColor: const Color(0xffA5A5A5), centerFontSize: 10) //
};
3. 包装根组件并链接主题

你需要将根组件包装在 ThemeScope 组件中,并使用 themeBuilder 来构建 MaterialApp。这样可以在运行时动态切换主题。

class MyApp extends StatelessWidget {
  final String initialTheme;

  const MyApp({Key? key, required this.initialTheme}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return ThemeScope<AppTheme>(
      themeId: initialTheme,
      availableThemes: appThemes,
      themeBuilder: (context, appTheme) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: appTheme.material,
          home: MyHomePage(title: 'Flutter Extended Theme'),
        );
      },
    );
  }
}
4. 获取主题属性

你可以在 widget 树中的任何地方通过 ThemeHolder.themeOf<AppTheme>(context) 获取主题属性。如果你只需要访问 Material 主题的属性,可以直接使用 Theme.of(context)

ThemeHolder.themeOf<AppTheme>(context).centerFontSize

或者:

Theme.of(context).textTheme.headline4
5. 更新主题

你可以在运行时通过 ThemeHolder.of<AppTheme>(context).updateThemeById('MagentaDark') 更新主题。

ThemeHolder.of<AppTheme>(context).updateThemeById('MagentaDark');

运行时构建主题

有时预定义的主题可能会限制灵活性。例如,如果你希望用户可以选择不同的字体大小,可以通过在运行时构建主题来实现。

1. 定义主题类(可选)

与前面相同,你可以继承 ExtendedTheme 类来定义自己的主题类。

2. 构建初始主题并传递给 ThemeScope

你可以在应用程序启动时构建初始主题,并将其传递给 ThemeScope

class MyApp extends StatelessWidget {
  final AppTheme initialTheme = AppTheme(ThemeData.light(), centerFontSize: 22, 
    subtitleColor: const Color(0xff8e8e8e));

  MyApp({Key? key}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return ThemeScope<AppTheme>(
      theme: initialTheme,
      themeBuilder: (context, appTheme) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: appTheme.material,
          home: MyHomePage(title: 'Flutter Extended Theme'),
        );
      },
    );
  }
}
3. 在运行时更新主题

你可以在运行时构建新的主题并更新当前主题。

// Build new theme
final newTheme = AppTheme(ThemeData.dark(), centerFontSize: 12, 
    subtitleColor: const Color(0xff8e8e8e));

// Update theme 
ThemeHolder.of<AppTheme>(context).updateTheme(newTheme);
4. 获取主题属性

获取主题属性的方式与前面相同。

处理亮度模式

你可以控制亮色和暗色主题,但需要在主题类中定义相应的属性。

class AppTheme extends ExtendedTheme {
  final ThemeData materialDark;

  AppTheme(ThemeData material, this.materialDark)
      : super(material: material);
}

然后将两个主题传递给 MaterialApp 构造函数:

class MyApp extends StatelessWidget {
  final String initialTheme;

  const MyApp({Key? key, required this.initialTheme}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return ThemeScope<AppTheme>(
      themeId: initialTheme,
      availableThemes: appThemes,
      themeBuilder: (context, appTheme) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: appTheme.material,
          darkTheme: appTheme.materialDark,
          home: MyHomePage(title: 'Flutter Extended Theme'),
        );
      },
    );
  }
}

完整示例代码

以下是一个完整的示例代码,展示了如何使用 extended_theme 插件来管理主题。

import 'package:extended_theme/extended_theme.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:google_fonts/google_fonts.dart';

class AppTheme extends ExtendedTheme {
  final Color? shadowColor;
  final Color? buttonPauseColor;
  final Color? subtitleColor;
  final double? centerFontSize;

  AppTheme(ThemeData material,
      {this.shadowColor,
      this.buttonPauseColor,
      this.subtitleColor,
      this.centerFontSize})
      : super(material: material);
}

ThemeData baseTheme = ThemeData(
  brightness: Brightness.light,
  textTheme: GoogleFonts.openSansTextTheme(ThemeData.light().textTheme),
);

ThemeData baseThemeDark = ThemeData(
  brightness: Brightness.dark,
  textTheme: GoogleFonts.openSansTextTheme(ThemeData.dark().textTheme),
);

const MagentaLight = 'MagentaLight';
const MagentaDark = 'MagentaDark';
const GreenLight = 'GreenLight';
const GreenDark = 'GreenDark';
const BlueLight = 'BlueLight';
const BlueDark = 'BlueDark';

final appThemes = {
  MagentaLight: AppTheme(
      baseTheme.copyWith(primaryColor: const Color(0xffcc0066)),
      subtitleColor: const Color(0xff8e8e8e),
      centerFontSize: 28),

  MagentaDark: AppTheme(
      baseThemeDark.copyWith(primaryColor: const Color(0xffcc0066)),
      subtitleColor: const Color(0xffA5A5A5),
      centerFontSize: 14),

  GreenLight: AppTheme(baseTheme.copyWith(primaryColor: Colors.green),
      subtitleColor: const Color(0xff8e8e8e), centerFontSize: 22),

  GreenDark: AppTheme(baseThemeDark.copyWith(primaryColor: Colors.green[700]),
      subtitleColor: const Color(0xffA5A5A5), centerFontSize: 12),

  BlueLight: AppTheme(baseTheme.copyWith(primaryColor: Colors.blue),
      subtitleColor: const Color(0xff8e8e8e), centerFontSize: 14),

  BlueDark: AppTheme(baseThemeDark.copyWith(primaryColor: Colors.blue[700]),
      subtitleColor: const Color(0xffA5A5A5), centerFontSize: 10) //
};

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  /// 从 SharedPreferences 中读取上次选择的主题
  final initialTheme = await _readLastTheme();

  runApp(MyApp(
    initialTheme: initialTheme,
  ));
}

Future<String> _readLastTheme() async {
  var prefs = await SharedPreferences.getInstance();

  final themeStr = prefs.getString('PREF_THEME') ?? GreenLight;
  return themeStr;
}

class MyApp extends StatelessWidget {
  final String initialTheme;

  const MyApp({Key? key, required this.initialTheme}) : super(key: key);

  [@override](/user/override)
  Widget build(BuildContext context) {
    return ThemeScope<AppTheme>(
      themeId: initialTheme,
      availableThemes: appThemes,
      themeBuilder: (context, appTheme) {
        debugPrint('Builder build');

        return MaterialApp(
          title: 'Flutter Demo',
          theme: appTheme.material,
          home: MyHomePage(title: 'Flutter Extended Theme'),
        );
      },
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, this.title}) : super(key: key);
  final String? title;

  [@override](/user/override)
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  [@override](/user/override)
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title!),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have changed the theme many times:',
              textAlign: TextAlign.center,
              style: TextStyle(
                  fontSize:
                      ThemeHolder.themeOf<AppTheme>(context).centerFontSize),
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        backgroundColor:
            ThemeHolder.themeOf<AppTheme>(context).buttonPauseColor,
        onPressed: () {
          final themeKeys = appThemes.keys.toList();
          ThemeHolder.of<AppTheme>(context)
              .updateThemeById(themeKeys[_counter % themeKeys.length]);

          _incrementCounter();
        },
        tooltip: 'Next theme',
        child: Icon(Icons.colorize),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

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

1 回复

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


当然,extended_theme 是一个强大的 Flutter 插件,用于管理和扩展应用的主题。它提供了灵活的机制来在应用运行时更改主题,并支持主题数据的持久化。以下是一个简单的示例,展示如何在 Flutter 应用中使用 extended_theme 插件。

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

dependencies:
  flutter:
    sdk: flutter
  extended_theme: ^x.y.z  # 替换为最新版本号

然后,运行 flutter pub get 以获取依赖。

接下来,设置你的应用以使用 ExtendedTheme。这里是一个基本的示例,展示如何设置和更改主题。

main.dart

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

void main() {
  runApp(ExtendedThemeWrapper(
    data: (ThemeData.light().copyWith(
      primaryColor: Colors.blue,
      accentColor: Colors.pink,
    )) as ThemeData?,
    defaultTheme: ThemeData.light(),
    builder: (context, theme) => MyApp(theme: theme!),
  ));
}

class MyApp extends StatelessWidget {
  final ThemeData theme;

  MyApp({required this.theme});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: theme,
      home: HomeScreen(),
    );
  }
}

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

class _HomeScreenState extends State<HomeScreen> {
  final ThemeMode initialThemeMode = ThemeMode.light;

  @override
  Widget build(BuildContext context) {
    final ExtendedThemeData themeData = ExtendedTheme.of(context)!;

    return Scaffold(
      appBar: AppBar(
        title: Text('Extended Theme Example'),
        actions: <Widget>[
          IconButton(
            icon: Icon(themeData.themeMode == ThemeMode.light
                ? Icons.dark_mode
                : Icons.lightbulb_outline),
            onPressed: () {
              setState(() {
                themeData.setThemeMode(
                  themeData.themeMode == ThemeMode.light
                      ? ThemeMode.dark
                      : ThemeMode.light,
                );
              });
            },
          ),
        ],
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              'Theme Mode: ${themeData.themeMode == ThemeMode.light ? "Light" : "Dark"}',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {},
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

关键点解释:

  1. ExtendedThemeWrapper:

    • 包装整个应用,用于提供和管理主题数据。
    • data 参数是初始主题数据。
    • defaultTheme 参数是默认主题数据,当没有持久化数据时使用。
    • builder 参数是一个函数,它接收上下文和当前主题数据,并返回应用的主部件。
  2. ExtendedTheme.of(context):

    • 用于在子部件中获取当前的 ExtendedThemeData 实例。
  3. 更改主题模式:

    • 使用 themeData.setThemeMode 方法来更改当前的主题模式(亮色或暗色)。

这个示例展示了如何使用 extended_theme 插件来管理和更改 Flutter 应用的主题。你可以根据需要进一步扩展和定制这个基础示例。

回到顶部