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個!!