Theme 组件可以为 Material APP 定义主题数据(ThemeData)。Material 组件库里很多组件都使用了主题数据,如导航栏颜色、标题字体、Icon 样式等。Theme 内会使用 InheritedWidget 来为其子树共享样式数据。
Theme 有两种: 全局 Theme 和 局部 Theme。 全局 Theme 是由应用程序根 MaterialApp 创建的 Theme 。
Theme 作用: 可以设置 Widget 的主题,提高开发效率和速度,保持 App 主题统一性或某种一致性。
全局主题:
/// 全局主题在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。
推荐站点(Material design):
https://material.io/resources/color,为你的 UI 创建共享调色板,并衡量任何颜色组合的可观性【非常实用的工具】。
实现效果:
分析:
这次是使用局部的实现,哪个页面需要同步就加个 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, // 设置为配置的主题数据
);
}
}