Flutter 支持全局设置 Theme 主题,需要配合 MaterialApp 的 theme 属性进行设置。主题在 Flutter 中主要是通过 ThemeData 来实现配置。
我们看一个最简单的用法:
///创建全局主题
Widget theme1() {
return MaterialApp(
///ThemeData.dark()
///ThemeData.light()
///默认有这两种主题
///也可以自定义主题,接近50种配置
theme: ThemeData(
brightness: Brightness.light,
primaryColor: Colors.lightBlue[800],
accentColor: Colors.cyan[600],
backgroundColor: Colors.white70,
),
home: Scaffold(
appBar: AppBar(
title: Text('Theme'),
),
body: Text(
'data',
style: TextStyle(fontSize: 18, decoration: TextDecoration.none),
),
),
);
}
ThemeData 提供了 ThemeData.light() 和 ThemeData.dark() 这两种已经配置好的色调主题,可以直接使用。当然,我们也可以自己配置 ThemeData 来实现个性化主题设置。如果 MaterialApp 没有设置主题的话也没关系,Flutter 会提供一个默认主题设置。
我们看下 ThemeData 有哪些属性可以配置:
factory ThemeData({
// 深色调还是浅色调
Brightness brightness,
// 主体颜色样本,可用于导航栏、FloatingActionButton的背景色等
MaterialColor primarySwatch,
// 主体的背景色,如导航
Color primaryColor,
// primaryColor的亮度:深色还是浅色
Brightness primaryColorBrightness,
// primaryColor的亮色调版本
Color primaryColorLight,
// primaryColor的暗色调版本
Color primaryColorDark,
// 前景色(文本、按钮等)
Color accentColor,
Brightness accentColorBrightness,
Color canvasColor,
// Scaffold的默认背景颜色
Color scaffoldBackgroundColor,
// BottomAppBar的默认颜色
Color bottomAppBarColor,
Color cardColor,
// 分割线颜色
Color dividerColor,
// 选中高亮的颜色
Color highlightColor,
// 按下波纹颜色
Color splashColor,
// 定义按下的效果外观
InteractiveInkFeatureFactory splashFactory,
// 选中行时的颜色
Color selectedRowColor,
// 非活动/未选中时颜色
Color unselectedWidgetColor,
// 不可用时颜色
Color disabledColor,
// 按钮颜色
Color buttonColor,
// 按钮主题
ButtonThemeData buttonTheme,
// 有选定行时PaginatedDataTable标题的颜色
Color secondaryHeaderColor,
// 文字选中时颜色
Color textSelectionColor,
// 指针光标颜色
Color cursorColor,
// 用于调整当前文本的哪个部分的句柄颜色
Color textSelectionHandleColor,
// 与primaryColor配合作为背景的颜色,如进度条的背景
Color backgroundColor,
// 对话框背景色
Color dialogBackgroundColor,
// 指示器颜色
Color indicatorColor,
// 提示文本的颜色
Color hintColor,
// 输入验证错误的颜色
Color errorColor,
// 切换活动状态的颜色
Color toggleableActiveColor,
// 字体
String fontFamily,
// 文本样式主题
TextTheme textTheme,
TextTheme primaryTextTheme,
TextTheme accentTextTheme,
// 输入框的主题
InputDecorationTheme inputDecorationTheme,
// 图标主题
IconThemeData iconTheme,
IconThemeData primaryIconTheme,
IconThemeData accentIconTheme,
// Slider主题
SliderThemeData sliderTheme,
// TabBar主题
TabBarTheme tabBarTheme,
// Card主题
CardTheme cardTheme,
// Chip主题
ChipThemeData chipTheme,
// 目标平台:android,ios,fuchsia
TargetPlatform platform,
MaterialTapTargetSize materialTapTargetSize,
// 页面过渡主题
PageTransitionsTheme pageTransitionsTheme,
// AppBar主题
AppBarTheme appBarTheme,
// BottomAppBar主题
BottomAppBarTheme bottomAppBarTheme,
ColorScheme colorScheme,
// Dialog主题
DialogTheme dialogTheme,
// FloatingActionButton主题
FloatingActionButtonThemeData floatingActionButtonTheme,
Typography typography,
// Cupertino主题
CupertinoThemeData cupertinoOverrideTheme,
})
可以看出,Flutter 主题可以全局配置的属性非常全面非常多。
通过 ThemeData 就可以简单配置出一个全局个性化主题:
theme: ThemeData(
brightness: Brightness.light,
primaryColor: Colors.lightBlue[800],
accentColor: Colors.cyan[600],
backgroundColor: Colors.white70,
),
有的时候我们不想使用全局的主题,而是想在某些页面有自己的风格样式,而 Flutter 也支持局部主题的设置。
我们可以通过局部主题去覆盖全局主题,此时我们需要借助 Theme 来实现:
// 局部主题覆盖全局主题
Widget theme2() {
return Theme(
data: ThemeData(
primaryColor: Colors.yellow[800],
accentColor: Colors.yellow[600],
backgroundColor: Colors.white,
),
child: Scaffold(
appBar: AppBar(
title: Text('Theme'),
),
body: Text(
'data',
style: TextStyle(fontSize: 18, decoration: TextDecoration.none),
),
),
);
}
我们只需要在最外层包裹一层 Theme 即可,然后 data 属性里重新配置个性化的 ThemeData 即可。child 属性放置原来的布局或者 Widget。
怎么样,是不是很灵活和简单!
有的时候我们不仅仅想使用局部主题,还需要进行修改全局主题或者扩展全局主题。例如手机QQ,支持手动切换全局主题等等。
那么我们就要借助 Theme.of(context).copyWith(…)
这个方法了。我们看下如何使用:
// 扩展或修改全局主题
Widget theme3(BuildContext context) {
return Theme(
data: Theme.of(context).copyWith(
// 修改全局主题primaryColor属性
primaryColor: Colors.white30,
),
child: Scaffold(
appBar: AppBar(
title: Text('Theme'),
),
body: Text(
'data',
style: TextStyle(
// 调用使用主题颜色
color: Theme.of(context).primaryColor,
fontSize: 18,
decoration: TextDecoration.none),
),
),
);
}
如果我们想使用主题中的一些属性值或者色调的话,可以通过 Theme.of(context) 来调用:
Container(
// 调用全局的主题accentColor色调值
color: Theme.of(context).accentColor,
child: Text(
'A Flutter Theme !',
style: Theme.of(context).textTheme.title,
),
);
当然我们可以根据不同平台使用不同 Theme。
通过 ThemeData 也可以完成换肤功能或者更换主题功能。