Theme
和局部Theme
。全局Theme
是由应用程序根MaterialApp
创建的Theme 。Widget
的主题,提高开发效率和速度,保持App主题统一性或某种一致性。Theme
组件可以为material
APP
定义主题数据(ThemeData
)。Material
组件库里很多组件都使用了主题数据, 如导航栏颜色、标题字体、Icon
样式等。Theme内会使用InheritedWidget
来为其子树共享样式数据。
/// 全局主题在MaterialApp的theme属性
/// 全局生效
new MaterialApp(
title: 'demo',
theme: new ThemeData( // 这里就是参数
brightness: Brightness.dark,
primaryColor: Colors.lightBlue[800],
accentColor: Colors.cyan[600],
),
);
/// 假如我们要给FloatingActionButton设置主题样式
/// 直接写个Theme包裹FloatingActionButton组件
/// 然后设置data,接收类型依然是ThemeData,里面填写我们的参数
/// (如果没有设置局部主题则默认使用全局主题)
new Theme(
data: new ThemeData(
accentColor: Colors.yellow,
),
child: new FloatingActionButton(
onPressed: () {},
child: new Icon(Icons.add),
),
);
/// 扩展父主题时无需覆盖所有的主题属性,可以通过使用copyWith方法来实现
new Theme(
data: Theme.of(context).copyWith(accentColor: Colors.yellow),
child: new FloatingActionButton(
onPressed: null,
child: new Icon(Icons.add),
),
);
Theme.of(context)
将查找Widget树并返回树中最近的Theme。如果Widget之上有一个单独的Theme定义, 则返回该值。如果不是,则返回App主题。
/// defaultTargetPlatform在foundation包里。
///
/// 我们也可以使用io包里的Platform来进行判断。
/// 那么判断就是
/// theme: Platform.isIOS ? iOSTheme : AndroidTheme,
new MaterialApp(
theme: defaultTargetPlatform == TargetPlatform.iOS
? iOSTheme
: AndroidTheme,
title: 'Flutter Theme',
home: new MyHomePage(),
);
Flutter的Color中大多数颜色从100到900,增量为100,加上颜色50,数字越小颜色越浅, 数字越大颜色越深。强调色调只有100、200、400和700。
https://material.io/resources/color,
为你的UI创建共享调色板,并衡量任何颜色组合的可观性【非常实用的工具】。
primaryColor
对比的颜色(例如 用作进度条的剩余部分)。BottomAppBar
的默认颜色。Material
中RaisedButtons
使用的默认填充色。MaterialType.canvas Material
的默认颜色。Material
被用作Card
时的颜色。Dialog
元素的背景色。Widget
无效的颜色,无论任何状态。例如禁用复选框。Dividers和PopupMenuDividers
的颜色,也用于ListTiles
中间,和DataTables的每行中间.TextField
中。TextField
中。TabBar
中选项选中的指示器颜色。ToolBar
,TabBar
等)。primaryColor
的较暗版本。primaryColor
的较亮版本。Scaffold
基础的Material
默认颜色,典型Material
应用或应用内页面的背景颜色。PaginatedDataTable
标题的颜色。TextField
。Widget
(如Switch
,Radio
和Checkbox
)的活动状态的颜色。Widget
处于非活动(但已启用)状态的颜色。例如,未选中的复选框。通常与accentColor
形成对比。IconThemeData
类型,与突出颜色对照的图片主题。TextTheme
类型,与突出颜色对照的文本主题。ChipThemeData
类型,用于渲染Chip
的颜色和样式。ButtonThemeData
类型,定义了按钮等控件的默认配置,像RaisedButton
和FlatButton
。IconThemeData
类型,一个与主色对比的图片主题。TextThemeData
类型,一个与主色对比的文本主题。IconThemeData
类型,与卡片和画布颜色形成对比的图标主题。InputDecorationTheme
类型,InputDecorator
,TextField
和TextFormField
的默认InputDecoration
值基于此主题。SliderThemeData
类型,用于渲染Slider
的颜色和形状。TextTheme
类型,与卡片和画布对比的文本颜色。ToggleButtonsThemeData
类型,Flutter 1.9 全新组件 ToggleButtons
的主题。TabBarTheme
类型,TabBar
的主题样式。TooltipThemeData
类型,tooltip
提示的主题样式。CardTheme
类型,卡片的主题样式。PageTransitionsTheme
类型,页面转场主题样式。AppBarTheme
类型,AppBar
主题样式。BottomAppBarTheme
类型,底部导航主题样式。DialogTheme
类型,对话框主题样式。FloatingActionButtonThemeData
类型,FloatingActionButton
的主题样式,也就是Scaffold
属性的那个。CupertinoThemeData
类型,cupertino
覆盖的主题样式。SnackBarThemeData
类型,弹出的snackBar
的主题样式。BottomSheetThemeData
类型,底部滑出对话框的主题样式。PopupMenuThemeData
类型,弹出菜单对话框的主题样式。MaterialBannerThemeData
类型,Material
材质的Banner
主题样式。DividerThemeData
类型,Divider
组件的主题样式,也就是那个横向线条组件。Brightness
类型,accentColor
的亮度。用于确定放置在突出颜色顶部的文本和图标的颜色(例如FloatingButton
上的图标)。Brightness
类型,应用程序整体主题的亮度。由按钮等Widget
使用,以确定在不使用主色或强调色时要选择的颜色。TargetPlatform
类型,Widget
需要适配的目标类型。InteractiveInkFeatureFactory
类型,定义InkWall
和InkResponse
生成的墨水喷溅的外观。Brightness
类型,primaryColor
的亮度。String
类型,字体样式。bool
类型,是否应用elevation
覆盖颜色。MaterialTapTargetSize
类型,Chip
等组件的尺寸主题设置,如:设置为MaterialTapTargetSize.shrinkWrap
时,clip
距顶部距离为0;设置为MaterialTapTargetSize.padded
时距顶部有一个距离ColorScheme
类型,scheme组颜色,一组13种颜色,可用于配置大多数组件的颜色属性。Typography
类型,用于配置TextTheme
、primaryTextTheme
和accentTextTheme
的颜色和几何文本主题值。这次是使用局部的实现,哪个页面需要同步就加个Theme就行了,全局也是类似的实现方式,主体代码不到100行。
首先写个配置类,主要配置主题的是否为黑夜模式和主题样式:
class Config {
static bool dark = true; // 是否为黑夜模式
static ThemeData themeData = new ThemeData.dark(); // 主题为暗色
}
然后我们正常的执行代码:
import 'package:flutter/material.dart';
import 'global_config.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(title: "Flutter高级进阶", home: new MyScaffold());
}
}
class MyScaffold extends StatefulWidget {
@override
_MyScaffoldState createState() => _MyScaffoldState();
}
class _MyScaffoldState extends State<MyScaffold> {
/*
* 主题改变
* */
changeTheme() {
if (Config.dark) {
Config.themeData = new ThemeData(
primaryColor: Colors.white,
scaffoldBackgroundColor: new Color(0xFFEBEBEB),
);
Config.dark = false;
} else {
Config.themeData = new ThemeData.dark();
Config.dark = true;
}
setState(() {});
}
Widget body(context) {
return new ListView(
children: <Widget>[
new Container(
width: MediaQuery.of(context).size.width / 4, // 整宽除4
child: new GestureDetector(
onTap: () => changeTheme(), // 触发更换主题的事件
child: new Column(
children: <Widget>[
new FlutterLogo(
size: 150.0,
style: FlutterLogoStyle.horizontal,
duration: Duration(milliseconds: 100),
textColor: Theme.of(context).colorScheme.background, // 从上下文拿到背景
),
new Text( // 如果为黑夜模式则按钮文字为白天模式,否则文字显示为黑夜模式
'点击Logo更换${Config.dark ? "白天模式" : "黑夜模式"}',
style: new TextStyle(fontSize: 25.0),
),
],
),
),
),
new MaterialButton( // 跳转按钮
onPressed: () {
Navigator.of(context).push(new MaterialPageRoute(
builder: (context) => new NewPage('Flutter高级进阶页面二')));
},
child: new Text('跳转到新页面'),
),
],
);
}
@override
Widget build(BuildContext context) {
return new Theme( // 主题组件,可设置局部的主题样式
data: Config.themeData, // 设置为配置的主题数据
child: new Scaffold(
appBar: new AppBar(elevation: 0),
body: body(context), // 身体页面body
),
);
}
}
再把NewPage测试页面写上:
class NewPage extends StatefulWidget {
final String title; // 接收的标题
NewPage(this.title);
@override
_NewPageState createState() => new _NewPageState(); // 创建有状态页面
}
class _NewPageState extends State<NewPage> {
@override
Widget build(BuildContext context) {
return new Theme(
child: new Scaffold( // title就是我们的标题
appBar: new AppBar(title: new Text('页面:${widget.title}'), elevation: 0),
body: new Center(
child: new Text(
'这是${widget.title}',
style: TextStyle(fontSize: 30.0),
),
),
),
data: Config.themeData, // 设置为配置的主题数据
);
}
}
直接复制到自己的项目内即可运行。