为了在整个应用中共享颜色和字体样式,我们可以使用主题。定义主题有两种方式:全局主题或使用Theme来定义应用程序局部的颜色和字体样式。 事实上,全局主题只是由应用程序根MaterialApp创建的Theme

定义一个主题后,我们可以在我们自己的Widgets中使用它。另外,Flutter提供的Material Widgets将使用我们的主题为AppBars、Buttons、Checkboxes等设置背景颜色和字体样式。

创建应用主题

为了在整个应用程序中共享包含颜色和字体样式的主题,我们可以提供ThemeDataMaterialApp的构造函数。

如果没有提供theme,Flutter将创建一个默认主题。

  1. new MaterialApp(
  2. title: title,
  3. theme: new ThemeData(
  4. brightness: Brightness.dark,
  5. primaryColor: Colors.lightBlue[800],
  6. accentColor: Colors.cyan[600],
  7. ),
  8. );

请参阅ThemeData文档以查看您可以定义的所有颜色和字体。

局部主题

如果我们想在应用程序的一部分中覆盖应用程序的全局的主题,我们可以将要覆盖得部分封装在一个Theme Widget中。

有两种方法可以解决这个问题:创建特有的ThemeData或扩展父主题。

创建特有的 ThemeData

如果我们不想继承任何应用程序的颜色或字体样式,我们可以通过new ThemeData()创建一个实例并将其传递给Theme Widget。

  1. new Theme(
  2. // Create a unique theme with "new ThemeData"
  3. data: new ThemeData(
  4. accentColor: Colors.yellow,
  5. ),
  6. child: new FloatingActionButton(
  7. onPressed: () {},
  8. child: new Icon(Icons.add),
  9. ),
  10. );

扩展父主题

扩展父主题时无需覆盖所有的主题属性,我们可以通过使用copyWith方法来实现。

  1. new Theme(
  2. // Find and Extend the parent theme using "copyWith". Please see the next
  3. // section for more info on `Theme.of`.
  4. data: Theme.of(context).copyWith(accentColor: Colors.yellow),
  5. child: new FloatingActionButton(
  6. onPressed: null,
  7. child: new Icon(Icons.add),
  8. ),
  9. );

使用主题

现在我们已经定义了一个主题,我们可以在Widget的build方法中通过Theme.of(context)函数使用它!

Theme.of(context)将查找Widget树并返回树中最近的Theme。如果我们的Widget之上有一个单独的Theme定义,则返回该值。如果不是,则返回App主题。 事实上,FloatingActionButton真是通过这种方式找到accentColor的!

下面看一个简单的示例:

  1. new Container(
  2. color: Theme.of(context).accentColor,
  3. child: new Text(
  4. 'Text with a background color',
  5. style: Theme.of(context).textTheme.title,
  6. ),
  7. );

完整的例子

  1. import 'package:flutter/foundation.dart';
  2. import 'package:flutter/material.dart';
  3. void main() {
  4. runApp(new MyApp());
  5. }
  6. class MyApp extends StatelessWidget {
  7. @override
  8. Widget build(BuildContext context) {
  9. final appName = 'Custom Themes';
  10. return new MaterialApp(
  11. title: appName,
  12. theme: new ThemeData(
  13. brightness: Brightness.dark,
  14. primaryColor: Colors.lightBlue[800],
  15. accentColor: Colors.cyan[600],
  16. ),
  17. home: new MyHomePage(
  18. title: appName,
  19. ),
  20. );
  21. }
  22. }
  23. class MyHomePage extends StatelessWidget {
  24. final String title;
  25. MyHomePage({Key key, @required this.title}) : super(key: key);
  26. @override
  27. Widget build(BuildContext context) {
  28. return new Scaffold(
  29. appBar: new AppBar(
  30. title: new Text(title),
  31. ),
  32. body: new Center(
  33. child: new Container(
  34. color: Theme.of(context).accentColor,
  35. child: new Text(
  36. 'Text with a background color',
  37. style: Theme.of(context).textTheme.title,
  38. ),
  39. ),
  40. ),
  41. floatingActionButton: new Theme(
  42. data: Theme.of(context).copyWith(accentColor: Colors.yellow),
  43. child: new FloatingActionButton(
  44. onPressed: null,
  45. child: new Icon(Icons.add),
  46. ),
  47. ),
  48. );
  49. }
  50. }