使用 Themes 统一颜色和字体风格
你可以使用主题来全局应用颜色和文字样式。
你可以定义应用全局的主题。你也可以为某一个组件单独继承一个特定的主题。每个主题都可以各自定义颜色、文字样式和其他 Material 配置参数。
Flutter 会按以下顺序应用样式:
-
针对特定 widget 的样式。
-
重载的继承主题的样式。
-
应用的总体样式。
在定义一个 Theme
之后,我们可以让它在指定的 widgets,包括 Flutter 自带的 Material widgets,例如
AppBars、Buttons、Checkboxes 等 widget 中生效。
Create an app theme
#全局 Theme 会影响整个 app 的颜色和字体样式。只需要向 MaterialApp
构造器传入 ThemeData
即可。
从 Flutter 3.16 版本开始, Material 3 是 Flutter 的默认主题。
如果没有手动配置主题,Flutter 将会使用预设的样式。
MaterialApp(
title: appName,
theme: ThemeData(
useMaterial3: true,
// Define the default brightness and colors.
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.purple,
// ···
brightness: Brightness.dark,
),
// Define the default `TextTheme`. Use this to specify the default
// text styling for headlines, titles, bodies of text, and more.
textTheme: TextTheme(
displayLarge: const TextStyle(
fontSize: 72,
fontWeight: FontWeight.bold,
),
// ···
titleLarge: GoogleFonts.oswald(
fontSize: 30,
fontStyle: FontStyle.italic,
),
bodyMedium: GoogleFonts.merriweather(),
displaySmall: GoogleFonts.pacifico(),
),
),
home: const MyHomePage(
title: appName,
),
);
大部分 ThemeData
实例会设置以下两个属性。它们会影响大部分样式属性。
-
colorScheme
定义了颜色。 -
textTheme
定义了文字样式。
你可以在 ThemeData
文档中查看所有可自定义的颜色和字体样式。
应用指定的主题
#要想应用你的主题,使用 Theme.of(context)
方法来指定 widget 的样式属性。其包括但不限于样式和颜色。
Theme.of(context)
会查询 widget 树,并返回其中最近的 Theme
。所以他会优先返回我们之前定义过的一个独立的 Theme
,如果找不到,它会返回全局主题。
在下面的例子中,Container
的颜色使用的就是指定主题(上层)的颜色。
Container(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 12,
),
color: Theme.of(context).colorScheme.primary,
child: Text(
'Text with a background color',
// ···
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Theme.of(context).colorScheme.onPrimary,
),
),
),
Override a theme
#你可以用 Theme
widget 嵌套想要改变主题的部分以进行主题重载。
以下是两种重载主题的方法:
-
构造一个不一样的
ThemeData
实例。 -
继承上层主题。
Set a unique ThemeData
instance
#如果不想从任何全局 Theme 继承样式,我们可以创建一个 ThemeData()
实例,然后把它传给 Theme
widget:
Theme(
// Create a unique theme with `ThemeData`.
data: ThemeData(
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.pink,
),
),
child: FloatingActionButton(
onPressed: () {},
child: const Icon(Icons.add),
),
);
Extend the parent theme
#相比从头开始定义一套样式,从上层 Theme 扩展可能更常规一些,使用 copyWith()
方法即可。
Theme(
// Find and extend the parent theme using `copyWith`.
// To learn more, check out the section on `Theme.of`.
data: Theme.of(context).copyWith(
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.pink,
),
),
child: const FloatingActionButton(
onPressed: null,
child: Icon(Icons.add),
),
);
观看 Theme
的相关视频
#
想要了解更多,你可以观看 Widget of the Week 中关于 Theme
的短视频:
Theme | Flutter widget of the week
交互式样例
#import 'package:flutter/material.dart';
// Include the Google Fonts package to provide more text format options
// https://pub.dev/packages/google_fonts
import 'package:google_fonts/google_fonts.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
const appName = 'Custom Themes';
return MaterialApp(
title: appName,
theme: ThemeData(
useMaterial3: true,
// Define the default brightness and colors.
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.purple,
// TRY THIS: Change to "Brightness.light"
// and see that all colors change
// to better contrast a light background.
brightness: Brightness.dark,
),
// Define the default `TextTheme`. Use this to specify the default
// text styling for headlines, titles, bodies of text, and more.
textTheme: TextTheme(
displayLarge: const TextStyle(
fontSize: 72,
fontWeight: FontWeight.bold,
),
// TRY THIS: Change one of the GoogleFonts
// to "lato", "poppins", or "lora".
// The title uses "titleLarge"
// and the middle text uses "bodyMedium".
titleLarge: GoogleFonts.oswald(
fontSize: 30,
fontStyle: FontStyle.italic,
),
bodyMedium: GoogleFonts.merriweather(),
displaySmall: GoogleFonts.pacifico(),
),
),
home: const MyHomePage(
title: appName,
),
);
}
}
class MyHomePage extends StatelessWidget {
final String title;
const MyHomePage({super.key, required this.title});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title,
style: Theme.of(context).textTheme.titleLarge!.copyWith(
color: Theme.of(context).colorScheme.onSecondary,
)),
backgroundColor: Theme.of(context).colorScheme.secondary,
),
body: Center(
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 12,
),
color: Theme.of(context).colorScheme.primary,
child: Text(
'Text with a background color',
// TRY THIS: Change the Text value
// or change the Theme.of(context).textTheme
// to "displayLarge" or "displaySmall".
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
color: Theme.of(context).colorScheme.onPrimary,
),
),
),
),
floatingActionButton: Theme(
data: Theme.of(context).copyWith(
// TRY THIS: Change the seedColor to "Colors.red" or
// "Colors.blue".
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.pink,
brightness: Brightness.dark,
),
),
child: FloatingActionButton(
onPressed: () {},
child: const Icon(Icons.add),
),
),
);
}
}
除非另有说明,本文档之所提及适用于 Flutter 的最新稳定版本,本页面最后更新时间: 2024-08-05。 查看文档源码 或者 为本页面内容提出建议。