Hello,你们好,又是很久没有水掘金了,我又回来啦!!今天给你们带来得仍是一个登陆页,不过今天这个登陆页又黑又亮,就像这个登陆页又白又长,夜间模式相信你们都不陌生,Andrid和iOS得全新版本也立刻要支持夜间模式了,因此本篇文章带你们简单粗略得认识下在Flutter中夜间模式怎么实现~bash
提及夜间模式其实并无什么神奇之处,只不过是资源得替换罢了,最简单得咱们能够设置一个变量isDark
用来判断是不是夜间模式,若是是则加载夜间资源若是不是则加载日间资源。 不过具体实现起来咱们就须要小小得开动下脑筋了less
InheritedWidget
来帮你咱们首先来思考第一个问题如何通知组件去更新替换资源,首先咱们能够想一想简单得两个组件间如何传递数据,咱们能够经过构造方法等比较粗暴得传入好比~ide
class Test {
var name;
Test(this.name);
}
class A extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(child: B(test: Test('苏武难飞')));
}
}
class B extends StatelessWidget {
final Test test;
const B({Key key, this.test}) : super(key: key);
@override
Widget build(BuildContext context) {
return Text(test.name);
}
}
复制代码
easy,可是啊可是,这种简单得传入只适合很是简单得页面逻辑交互时使用,想一想一下咱们某个页面有七八个甚至于更多组件时,这样传数据简直就是,逻辑地狱呀Flutter
得开发团队显然也是意识到这点了因此咱们本篇得主角InheritedWidget
就该出场了!post
InheritedWidget
能够作啥鸭?简而言之,InheritedWidget 容许在 widget 树中有效地向下传播(和共享)信息。 InheritedWidget 是一个特殊的 Widget,它将做为另外一个子树的父节点放置在 Widget 树中。该子树的全部 widget 都必须可以与该 InheritedWidget 暴露的数据进行交互。字体
举个🌰子,咱们有一个TodoList
应用,有一个页面A列表页,有一个B添加页 ui
InheritedWidget
InheritedWidget
怎样使用class _TodoInherited extends InheritedWidget {
_TodoInherited({Key key, @required Widget child, this.data})
: super(key: key, child: child);
final TodoState data;
@override
bool updateShouldNotify(InheritedWidget oldWidget) {
return true;
}
}
复制代码
很是简单,InheritedWidget
得特殊性在于它做为一个树节点其全部得子节点均可以可以与该InheritedWidget
暴露得数据进行交互。又因为要使用InheritedWidget
得时候咱们的数据大部分都是须要动态改变得,So,咱们势必要使用StatefulWidget
,那么咱们得完整代码就应该以下:this
class Todo {
String title;
Todo(this.title);
}
class _TodoInherited extends InheritedWidget {
_TodoInherited({Key key, @required Widget child, this.data})
: super(key: key, child: child);
final TodoState data;
@override
bool updateShouldNotify(InheritedWidget oldWidget) {
return true;
}
}
class TodoWidget extends StatefulWidget {
final Widget child;
TodoWidget({Key key, this.child}) : super(key: key);
static TodoState instanceOf(BuildContext context) {
_TodoInherited inherited = (context
.inheritFromWidgetOfExactType(_TodoInherited) as _TodoInherited);
return inherited.data;
}
@override
State<StatefulWidget> createState() => TodoState();
}
class TodoState extends State<TodoWidget> {
List<Todo> _todoList = [];
List<Todo> get todoList => _todoList;
void addTodo(String title) {
setState(() {
_todoList.add(Todo(title));
});
}
@override
Widget build(BuildContext context) {
// TODO: implement build
return new _TodoInherited(child: widget.child, data: this);
}
}
复制代码
Todo
做为咱们得数据模型保存在TodoState
中_TodoInherited
中保存TodoState
得引用,方便调用获取Todo
_TodoInherited
中的updateShouldNotify
方法是用来判断是否更新重建TodoWidget
中的instanceOf
方法是用来获取TodoState
方便获取其中的数据instanceOf
中的context.inheritFromWidgetOfExactType
是用来注册绑定InheritedWidget
因此咱们的完整业务代码应该以下:spa
void main() {
runApp(TodoWidget(child: MyApp()));
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'TodoList', debugShowCheckedModeBanner: false, home: HomePage());
}
}
class HomePage extends StatelessWidget {
Widget buildEmpty() {
return ...;
}
Widget buildList(List<Todo> list) {
return ...;
}
@override
Widget build(BuildContext context) {
List<Todo> list = TodoWidget.instanceOf(context).todoList;
return list.isEmpty ? buildEmpty() : buildList(list);
}
}
class AddTaskPage extends StatelessWidget {
final controller = TextEditingController();
void closeTask(BuildContext context) {
Navigator.pop(context);
}
Widget getTextField() {
return TextField(controller: controller);
}
@override
Widget build(BuildContext context) {
return onTap: () {
TodoWidget.instanceOf(context).addTodo(controller.text);
closeTask(context);
}
}
}
复制代码
相信你们理解了上面的内容对于夜间模式的实现应该也是胸中有竹子啦~我这边介绍一个实现方法debug
class _CustomTheme extends InheritedWidget {
final CustomThemeState data;
_CustomTheme({this.data, Key key, @required Widget child})
: super(key: key, child: child);
@override
bool updateShouldNotify(InheritedWidget oldWidget) {
// TODO: implement updateShouldNotify
return true;
}
}
class CustomTheme extends StatefulWidget {
final Widget child;
final MyThemeKeys initialThemeKey;
const CustomTheme({Key key, this.initialThemeKey, this.child})
: super(key: key);
@override
CustomThemeState createState() => CustomThemeState();
static ThemeModel of(BuildContext context) {
_CustomTheme inherited =
(context.inheritFromWidgetOfExactType(_CustomTheme) as _CustomTheme);
return inherited.data.theme;
}
static CustomThemeState instanceOf(BuildContext context) {
_CustomTheme inherited =
(context.inheritFromWidgetOfExactType(_CustomTheme) as _CustomTheme);
return inherited.data;
}
}
class CustomThemeState extends State<CustomTheme> {
ThemeModel _model;
ThemeModel get theme => _model;
@override
void initState() {
_model = MyThemes.getThemeFromKey(widget.initialThemeKey);
super.initState();
}
void changeTheme(MyThemeKeys themeKey) {
print(themeKey);
setState(() {
_model = MyThemes.getThemeFromKey(themeKey);
});
}
@override
Widget build(BuildContext context) {
return _CustomTheme(data: this, child: widget.child);
}
}
enum MyThemeKeys { LIGHT, DARK }
class MyThemes {
static final ThemeModel lightTheme = ThemeModel(
imageUrl: 'assets/images/banner.png',
backgroundColor: Color(0xffffffff),
titleColor: Color(0xff3C4859),
borderColor: Colors.black.withOpacity(0.3),
isDark: false);
static final ThemeModel darkTheme = ThemeModel(
imageUrl: 'assets/images/banner_dark.png',
backgroundColor: Color(0xff2B1C71),
titleColor: Color(0xffffffff),
borderColor: Colors.white.withOpacity(0.3),
isDark: true);
static ThemeModel getThemeFromKey(MyThemeKeys themeKey) {
switch (themeKey) {
case MyThemeKeys.LIGHT:
return lightTheme;
case MyThemeKeys.DARK:
return darkTheme;
default:
return lightTheme;
}
}
}
void main() {
runApp(CustomTheme(initialThemeKey: MyThemeKeys.LIGHT, child: MyApp()));
}
class MyApp extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
debugShowCheckedModeBanner: false,
home: HomePage());
}
}
复制代码
而后咱们字体或者颜色等能够直接从ThemeModel
中获取,可是有一些比较特殊的状况可能须要特殊处理时,Flutter
也能很是优雅方便的处理,好比:3d
Widget build(BuildContext context) {
String image = CustomTheme.of(context).imageUrl;
bool isDark = CustomTheme.of(context).isDark;
Widget child = isDark
? Padding(...)
: Padding(...);
return child;
}
复制代码
Ok,至此咱们的夜间模式也算是实现了~
本篇依然是一个很是简单的内容分享,可是InheritedWidget
是一个很是实用好用的组件,但愿你们都熟练掌握!!登陆页系列还在继续,请你们敬请期待吧~ 距离掘金社区50个赞还差7个!!