開始介紹inheritedWidget
之前,先來介紹一個 知識點 為後面的內容做鋪墊
先介紹ancestorWidgetOfExactType
1. 先看下 Demo 程式碼結構
demo
地址: github.com/LZQL/flutte…
可以說是目前 全網 最完整的demo
演示了
2. ancestorWidgetOfExactType
返回給定型別的最近父widget
,該widget
的型別必須是具體widget
的子類。
一般來說,inheritFromWidgetOfExactType
更有用,因為繼承的widget
將在更改時觸發消費者重新構建。ancestorWidgetOfExactType
適用於互動事件處理程式(例如手勢回撥)或執行一次性任務,例如斷言
您擁有或不具有作為特定型別的父widget
。widget
的構建方法的返回值不應該依賴於該方法返回的值,因為如果該方法的返回值發生更改,構建上下文將不會重新生成
。這可能會導致生成方法中使用的資料發生更改,但是沒有重新生成widget
。
總結一下上面的意思:
ancestorWidgetOfExactType
一般用於 斷言,是否有特定型別的父widget
ancestorWidgetOfExactType
可以用來獲取父widget
的一些資訊- 如果想要根據方法的返回值來判斷是否重新構建,
ancestorWidgetOfExactType
並不適用
下面會分別給出 上面的3
點總結來給出demo
場景
1. 斷言
這邊就不給出自己的demo
,直接看原始碼,原始碼的應用場景說明一切,這邊也是官方翻譯的最好證明
Hero
的原始碼,做了斷言,斷言就寫到這裡
2. 獲取父widget
的一些資訊
1. 程式碼結構
2. 執行效果
WidgeC
是一個 加號按鈕, 點選了WidgeC
,獲取HomepageState
呼叫incrementCounter
方法,
, widgetA
,widgetB
,widgetC
會重新build
,看下圖
3. 具體程式碼
程式碼位置 ancestor01.dart
/// ancestorWidgetOfExactType 獲取父widget的一些資訊
class MyAncestorTree01 extends StatefulWidget {
@override
_MyAncestorTree01State createState() => _MyAncestorTree01State();
}
class _MyAncestorTree01State extends State<MyAncestorTree01> {
@override
Widget build(BuildContext context) {
return TopPage01();
}
}
class TopPage01 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('Demo'),
),
body: HomePage(),
),
);
}
}
class HomePage extends StatefulWidget {
final HomePageState state = HomePageState();
@override
HomePageState createState() {
return state;
}
}
class HomePageState extends State<HomePage> {
int counter = 0;
void incrementCounter() {
setState(() {
counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
WidgetA(),
WidgetB(),
WidgetC(),
],
),
);
}
}
class WidgetA extends StatelessWidget {
@override
Widget build(BuildContext context) {
/// 獲取 HomePageState 來獲取 counter
final HomePage widget =
context.ancestorWidgetOfExactType(HomePage);
final HomePageState state = widget?.state;
return Center(
child: Text(
'${state == null ? 0 : state.counter}',
style: Theme.of(context).textTheme.display1,
),
);
}
}
class WidgetB extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Text('Widget B Text');
}
}
class WidgetC extends StatelessWidget {
@override
Widget build(BuildContext context) {
/// 獲取 HomePageState 來 呼叫 加法操作
final HomePage widget = context.ancestorWidgetOfExactType(HomePage);
final HomePageState state = widget?.state;
return RaisedButton(
onPressed: () {
state?.incrementCounter();
},
child: Icon(Icons.add),
);
}
}
複製程式碼
3. 子widget無法檢測到父widget的更改
此demo
用來演示 子widget無法檢測到父widget的更改
的具體情況
為後面的內容做鋪墊
我將ancestorWidgetOfExactType
封裝了一個 of 方法放到了TopPage02
裡面,
與 2. 獲取父widget 的一些資訊
的使用場景不同。
1. 程式碼結構
2. 執行效果
注意看下圖,當我點選了1 - AncestorWidgetOfExactType02 演示
按鈕,進入 demo
頁面,從右側可以看出,因為是第一次進去,所以全部widget
都進行了build
操作,但是當我 點選 了Add item
按鈕,TopPage02
會rebuild
但是WidgetA
, WidgetB
,WidgetC
,並不會進行rebuild
3. 具體程式碼
程式碼位置ancestor02.dart
/// ancestorWidgetOfExactType
/// 子widget無法檢測到父widget的更改
/// (父widget rebuild 子widget no rebuild)
class MyAncestorTree02 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new TopPage02(
child: new Scaffold(
appBar: new AppBar(
title: new Text('Title'),
),
body: new Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
new WidgetA(),
new WidgetB(),
new WidgetC(),
],
),
),
);
}
}
class Item {
String reference;
Item(this.reference);
}
class TopPage02 extends StatefulWidget {
TopPage02({
Key key,
this.child,
}) : super(key: key);
final Widget child;
final TopPage02State state = new TopPage02State();
@override
TopPage02State createState() {
return state;
}
static TopPage02State of(BuildContext context) {
/// 通過從 TopPage02 的 context 得到樹結構來返回第一個 TopPage02State
return (context.ancestorWidgetOfExactType(TopPage02)
as TopPage02)
.state;
}
}
class TopPage02State extends State<TopPage02> {
List<Item> _items = <Item>[];
int get itemsCount => _items.length;
void addItem(String reference) {
setState(() {
_items.add(new Item(reference));
});
}
@override
Widget build(BuildContext context) {
return widget.child;
}
}
class WidgetA extends StatefulWidget {
@override
_WidgetAState createState() => _WidgetAState();
}
class _WidgetAState extends State<WidgetA> {
@override
Widget build(BuildContext context) {
final TopPage02State state = TopPage02.of(context);
return new Center(
child: new RaisedButton(
child: new Text('WidgetA :Add Item'),
onPressed: () {
/// 這邊呼叫 addItem 方法,但是WidgetA,WidgetB,WidgetC
/// 並不會 build
/// 這就說明了:widget的構建方法的返回值不應該依賴於該方法返回的值,
/// 因為如果該方法的返回值發生更改,構建上下文將不會重新生成。
/// 這可能會導致生成方法中使用的資料發生更改,但是沒有重新生成widget
state.addItem('new item');
},
),
);
}
}
class WidgetB extends StatelessWidget {
@override
Widget build(BuildContext context) {
final TopPage02State state = TopPage02.of(context);
return new Text('widgetB itemCount:${state.itemsCount}');
}
}
class WidgetC extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Text('I am Widget C');
}
}
複製程式碼
3. InheritedWidget
1. 什麼是 InheritedWidget
特性:
InheritedWidget
是一個可以在樹中高效地向下傳遞資料
的元件:我們可以在以InheritedWidget
為節點的樹下任一Widget
中呼叫BuildContext.inheritFromWidgetOfExactType
來獲取離其最近的InheritedWidget
例項- 當以上面這種方式(呼叫
inheritFromWidgetOfExactType
方法時)被引用後,每當InheritedWidget
自身的狀態改變時,會導致“consumer”
(呼叫inheritFromWidgetOfExactType
方法的這個Child
) 重新build
第一點:在Flutter
中,正是通過InheritedWidget
來共享應用主題(Theme
)和Locale
(當前語言環境)資訊的
第二點:解決了 上面提到ancestorWidgetOfExactType
的第三點不能通過返回值來進行重新build
的情況
InheritedWidget
的在Widget
樹中資料傳遞方向是從上到下的,這和Notification
的傳遞方向正好相反。(後面系列文章介紹Notification
)
2. didChangeDependencies
StatefulWidget
的State
物件有一個回撥didChangeDependencies
,它會在“依賴”發生變化時被Flutter Framework
呼叫。而這個“依賴”指的就是是否使用了父widget
中InheritedWidget
的資料,如果使用了,則代表有依賴,如果沒有使用則代表沒有依賴。這種機制可以使子元件在所依賴的主題、locale
等發生變化時有機會來做一些事情。
4. 通過 2 - InheritedWidget演示01
,發現問題
這個例子 是參照 book.flutterchina.club/chapter7/in… 寫的一樣,相信很多人都看過
1. 程式碼結構
2. 效果圖
當我點選了 click me
按鈕 加1,widgetA
,widgeB
,RaisedButton
會重新build
3. 程式碼
程式碼位置:inheritedwidget01.dart
/// InheritedWidget01 , 會導致 `widgetA`,` widgeB`,`RaisedButton `會重新`build`
class InheritedWidgetTest01 extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return InheritedWidgetTest01State();
}
}
class InheritedWidgetTest01State extends State<InheritedWidgetTest01> {
int tmpData = 0;
@override
Widget build(BuildContext context) {
print('InheritedWidgetTest01 build');
return Scaffold(
body: Center(
child: ShareInherited(
data: tmpData,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
WidgetA(),
WidgetB(),
RaisedButton(
child: Text("Click me"),
onPressed: () {
setState(() {
print('onPressed');
tmpData += 1;
});
},
),
],
),
),
),
);
}
}
class ShareInherited extends InheritedWidget {
final int data; //需要在子樹中共享的資料,儲存點選次數
ShareInherited({@required this.data, @required Widget child}) : super(child: child) {
print('ShareInherited construct');
}
/// 允許所有子 widget 通過包含的 context 獲得最近的 ShareInherited 例項
/// 定義一個便捷方法,方便子樹中的widget獲取共享資料
/// 在內部,除了簡單地返回 ShareInherited 例項外,它還訂閱消費者 widget 以便用於通知更改
static ShareInherited of(BuildContext context) {
return context.inheritFromWidgetOfExactType(ShareInherited);
}
/// 用來告訴 InheritedWidget 如果對資料進行了修改,
/// 是否必須將通知傳遞給所有子 widget(已註冊/已訂閱)
@override
bool updateShouldNotify(ShareInherited oldWidget) {
// 如果返回true,則子樹中依賴(build函式中有呼叫)本widget
// 的子widget的`state.didChangeDependencies`會被呼叫
bool result = oldWidget.data != this.data;
print('ShareInherited updateShouldNotify result = $result');
return result;
}
}
class WidgetA extends StatefulWidget {
@override
_WidgetAState createState() => _WidgetAState();
}
class _WidgetAState extends State<WidgetA> {
@override
Widget build(BuildContext context) {
print('WidgetA build');
int data = ShareInherited.of(context).data;
return Text('WidgetA data = $data');
}
@override
void didChangeDependencies() {
print('WidgetA didChangeDependencies');
super.didChangeDependencies();
}
}
class WidgetB extends StatefulWidget {
@override
_WidgetBState createState() => _WidgetBState();
}
class _WidgetBState extends State<WidgetB> {
@override
Widget build(BuildContext context) {
print('WidgetB build');
return Text('WidgetB');
}
@override
void didChangeDependencies() {
print('WidgetB didChangeDependencies');
super.didChangeDependencies();
}
}
複製程式碼
4. 發現的現象
WidgetA
呼叫了inheritFromWidgetOfExactType
方法,獲得了存放在 ShareInherited
物件裡的data
資料並顯示在WidgetA
內容上,同時使得 WidgetA
和ShareInherited
產生關聯;
當點選 RaisedButton
觸發InheritedWidgetTest01
狀態更新時,InheritedWidgetTest01State
的 build
方法回撥,重新構建 ShareInherited
物件傳入新值,由於data
發生變化,ShareInherited
的方法updateShouldNotify
中返回了true
,最終使得與ShareInherited
關聯的WidgetA
觸發reBuild
。
當我們執行並點選RaisedButton
後,頁面表現得確實如上述所示,WidgetA
的內容由 WidgetA data = 0
變為了WidgetA data = 1
,似乎 InheritedWidget
正確的使用方式正是如此,但是log
裡輸出的卻是如下:
I/flutter (11303): onPressed
I/flutter (11303): InheritedWidgetTest01 build
I/flutter (11303): ShareInherited construct
I/flutter (11303): ShareInherited updateShouldNotify result = true
I/flutter (11303): WidgetA didChangeDependencies
I/flutter (11303): WidgetA build
I/flutter (11303): WidgetB build
複製程式碼
可以看到,結合前面的程式碼邏輯分析,理論上只有 WidgetA
才會reBuild
,而現在卻產生了I/flutter (11303): WidgetB build
這條記錄。這是為什麼呢?
5. 原因分析
其實可以從前面提到的特性2
找到答案。其中說到:InheriteWidget
狀態發生變化時會rebuild
相關的child
。 我們知道,flutter
中Widget
被標識為了@immutable
,即是不可變的,那麼所謂的狀態發生變化就意味著InheriteWidget
重新構建,由於前面程式碼中在InheriteWidget
構造時同時也構造的其child
物件,因此當InheriteWidget
重新構建時也會導致child
跟著重新構建,這樣也就失去了“rebuild相關的child”
的意義,
也就是說,要想特性2生效,需要保證
InheriteWidget
節點下的樹不會被重新構建。
5. 解決方法1:使用 const Widget
將InheriteWidget
的child
轉化為const
,這樣即使在重建 InheriteWidget
時,由於其child
得到的是同一個物件,也就不會導致這個子樹重建,選擇性reBuild
也就得到了保證。但是由於const
特性,相關的引數也必須是常量,因此需要重寫或修改的程式碼量相對較多,因此更推薦解決方法2
的做法,這個方法在後面回寫
1. const demo 01,發現問題
1. 程式碼結構
2. 效果圖
WidgeA
,WidgeB
,FlatButton
是處於同一級別的
從下圖可以看到 當我點選了click me
,widgetB
並不會被 rebuild
, 但是 WidgeA
和FlatButton
會rebuild
,這樣解決了WidgeB rebuild
的問題,但是 FlateButton
並不涉及到 頁面的資料重新整理,如果我想要讓 FlatButton
也不rebuild
呢? 看const
的demo02
3. 程式碼
程式碼位置:inheritedwidget_const_01.dart
/// 使用 const
/// Widget A ,FlatButton rebuild, Widget B no rebuild
class InheritedWidgetConst01 extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return InheritedWidgetConst01State();
}
}
class InheritedWidgetConst01State extends State<InheritedWidgetConst01> {
int tmpData = 0;
@override
Widget build(BuildContext context) {
print('InheritedWidgetTest02 build');
return Scaffold(
body: Center(
child: ShareInherited(
data: tmpData,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const WidgetA(),
const WidgetB(),
FlatButton(
child: Text("Click me"),
onPressed: () {
setState(() {
print('onPressed');
tmpData += 1;
});
},
),
],
),
),
),
);
}
}
class ShareInherited extends InheritedWidget {
final int data;
ShareInherited({this.data, @required Widget child}) : super(child: child) {
print('ShareInherited construct');
}
@override
bool updateShouldNotify(ShareInherited oldWidget) {
bool result = oldWidget.data != this.data;
print('ShareInherited updateShouldNotify result = $result');
return result;
}
static ShareInherited of(BuildContext context) {
return context.inheritFromWidgetOfExactType(ShareInherited);
}
}
class WidgetA extends StatelessWidget {
const WidgetA();
@override
Widget build(BuildContext context) {
print('WidgetA build');
int data = ShareInherited.of(context).data;
return Text('WidgetA data = $data');
}
}
class WidgetB extends StatelessWidget {
const WidgetB();
@override
Widget build(BuildContext context) {
print('WidgetB build');
return Text('WidgetB');
}
}
複製程式碼
2. const demo 02,繼續發現問題
1. 程式碼結構
2. 效果圖
你會發現,WidgeA
和 WidgeC
還是rebuild
, 要解決這個問題,就需要用到 文章頂部提到的ancestorWidgetOfExactType
了,看 const demo 03,終極寫法
3. 程式碼
程式碼位置 inheritedwidget_const_02.dart
/// 使用 const
/// Widget A ,Widget C rebuild, Widget B no rebuild
class InheritedWidgetConst02 extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return InheritedWidgetConst02State();
}
}
class InheritedWidgetConst02State extends State<InheritedWidgetConst02> {
int tmpData = 0;
void addItem(){
setState(() {
tmpData++;
});
}
@override
Widget build(BuildContext context) {
print('InheritedWidgetTest02 build');
return Scaffold(
body: Center(
child: ShareInherited(
data: tmpData,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const WidgetA(),
const WidgetB(),
WidgetC(),
],
),
state: this,
),
),
);
}
}
class ShareInherited extends InheritedWidget {
final int data;
final InheritedWidgetConst02State state;
ShareInherited({this.data, @required Widget child,this.state}) : super(child: child) {
print('ShareInherited construct');
}
@override
bool updateShouldNotify(ShareInherited oldWidget) {
bool result = oldWidget.data != this.data;
print('ShareInherited updateShouldNotify result = $result');
return result;
}
static ShareInherited of(BuildContext context) {
return context.inheritFromWidgetOfExactType(ShareInherited);
}
}
class WidgetA extends StatelessWidget {
const WidgetA();
@override
Widget build(BuildContext context) {
print('WidgetA build');
int data = ShareInherited.of(context).data;
return Text('WidgetA data = $data');
}
}
class WidgetB extends StatelessWidget {
const WidgetB();
@override
Widget build(BuildContext context) {
print('WidgetB build');
return Text('WidgetB');
}
}
class WidgetC extends StatefulWidget {
@override
_WidgetCState createState() => _WidgetCState();
}
class _WidgetCState extends State<WidgetC> {
@override
Widget build(BuildContext context) {
print('Widge C build');
InheritedWidgetConst02State state = ShareInherited.of(context).state;
return FlatButton(
child: Text("Click me"),
onPressed: () {
setState(() {
print('onPressed');
state.addItem();
});
},
);
}
}
複製程式碼
3. const demo 03,終極寫法
1. 程式碼結構
2. 效果圖
ShareInherited
的of
方法 ,增加了 是否 rebuild
的引數
你會發現 ,現在只有WidgeA
會rebuild
,完美啊
static ShareInherited of([BuildContext context, bool rebuild = true]) {
return (rebuild
? context.inheritFromWidgetOfExactType(ShareInherited)
: context.ancestorWidgetOfExactType(ShareInherited) );
}
複製程式碼
3. 程式碼
程式碼位置inheritedwidget_const_03.dart
/// 使用 const
/// Widget A rebuild, Widget B Widget C no rebuild
class InheritedWidgetConst03 extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return InheritedWidgetConst03State();
}
}
class InheritedWidgetConst03State extends State<InheritedWidgetConst03> {
int tmpData = 0;
void addItem() {
setState(() {
tmpData++;
});
}
@override
Widget build(BuildContext context) {
print('InheritedWidgetTest02 build');
return Scaffold(
body: Center(
child: ShareInherited(
data: tmpData,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const WidgetA(),
const WidgetB(),
const WidgetC(),
],
),
state: this,
),
),
);
}
}
class ShareInherited extends InheritedWidget {
final int data;
final InheritedWidgetConst03State state;
ShareInherited({this.data, @required Widget child, this.state})
: super(child: child) {
print('ShareInherited construct');
}
@override
bool updateShouldNotify(ShareInherited oldWidget) {
bool result = oldWidget.data != this.data;
print('ShareInherited updateShouldNotify result = $result');
return result;
}
static ShareInherited of([BuildContext context, bool rebuild = true]) {
return (rebuild
? context.inheritFromWidgetOfExactType(ShareInherited)
: context.ancestorWidgetOfExactType(ShareInherited) );
}
}
class WidgetA extends StatelessWidget {
const WidgetA();
@override
Widget build(BuildContext context) {
print('WidgetA build');
int data = ShareInherited
.of(context)
.data;
return Text('WidgetA data = $data');
}
}
class WidgetB extends StatelessWidget {
const WidgetB();
@override
Widget build(BuildContext context) {
print('WidgetB build');
return Text('WidgetB');
}
}
class WidgetC extends StatelessWidget {
const WidgetC();
@override
Widget build(BuildContext context) {
print('Widge C build');
InheritedWidgetConst03State state = ShareInherited.of(context,false).state;
return FlatButton(
child: Text("Click me"),
onPressed: () {
print('onPressed');
state.addItem();
},
);
}
}
複製程式碼
6. 解決方法2:上移Child
物件到InheriteWidget
的Parent Widget
1. out demo 01,發現問題
1. 程式碼結構
2. 效果圖
具體看程式碼吧,稍顯複雜 ,這邊命名不是很規範,懶得改了, 太累了寫demo
,看程式碼可以知道
class ShareInherited extends StatelessWidget
複製程式碼
這裡的ShareInherited
是一個 StatelessWidget
,也就是 上移了Child
物件到InheriteWidget
的Parent Widget
class _ShareInherited extends InheritedWidget
複製程式碼
而_ShareInherited
才是 具體的 InheritedWidget
看下圖可知 Widget A ,FlatButton rebuild, Widget B no rebuild
這時候我們 一樣的 把 FlatButton
放到 WidgetC
然後上移到 InheriteWidget
的Parent Widget
看能不能實現讓
WidgeC
no rebuild
3. 程式碼
程式碼位置inheritedwidget_out_01.dart
/// 上移`Child`物件到`InheriteWidget`的`Parent Widget`
/// Widget A ,FlatButton rebuild, Widget B no rebuild
class InheritedWidgetOut01 extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return InheritedWidgetOut01State();
}
}
class InheritedWidgetOut01State extends State<InheritedWidgetOut01> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: MyWidget(
Column(
children: <Widget>[
WidgetA(),
WidgetB()
],
)
),
);
}
}
class MyWidget extends StatefulWidget {
final Widget child;
MyWidget(this.child);
@override
_MyWidgetState createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
int tempData = 0;
@override
Widget build(BuildContext context) {
return ShareInherited(
data: tempData,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
widget.child,
FlatButton(
child: Text("Click me"),
onPressed: () {
setState(() {
print('onPressed');
tempData += 1;
});
},
)
],
),
),
);
}
}
class ShareInherited extends StatelessWidget {
final int data;
final Widget child;
ShareInherited({
Key key,
this.data,
this.child
}): assert(child != null),
assert(data != null),
super(key: key);
static int of(BuildContext context) {
final _ShareInherited inheritedTheme = context.inheritFromWidgetOfExactType(_ShareInherited);
return inheritedTheme.shareInherited.data;
}
@override
Widget build(BuildContext context) {
return _ShareInherited(shareInherited:this , child: child,);
}
}
class _ShareInherited extends InheritedWidget{
final ShareInherited shareInherited;
_ShareInherited({
Key key,
@required this.shareInherited,
@required Widget child,
}):assert(shareInherited != null),
super(key: key, child: child);
@override
bool updateShouldNotify(_ShareInherited oldWidget) {
return shareInherited.data != oldWidget.shareInherited.data;
}
}
class WidgetA extends StatelessWidget {
@override
Widget build(BuildContext context) {
print('WidgetA build');
int data = ShareInherited.of(context);
return Text('WidgetA data = $data');
}
}
class WidgetB extends StatelessWidget {
@override
Widget build(BuildContext context) {
print('WidgetB build');
return Text('WidgetB');
}
}
複製程式碼
2. out demo 02,繼續發現問題
1. 程式碼結構
2. 效果圖
你會發現 Widget A ,Widget C rebuild, Widget B no rebuild
如果想要 讓 Widge C no rebuild,看out demo 03
3. 程式碼
程式碼位置inheritedwidget_out_02.dart
/// 上移`Child`物件到`InheriteWidget`的`Parent Widget`
/// Widget A ,Widget C rebuild, Widget B no rebuild
class InheritedWidgetOut02 extends StatefulWidget {
@override
_InheritedWidgetOut02State createState() => new _InheritedWidgetOut02State();
}
class _InheritedWidgetOut02State extends State<InheritedWidgetOut02> {
@override
Widget build(BuildContext context) {
return new MyInheritedWidget(
child: new Scaffold(
appBar: new AppBar(
title: new Text('Title'),
),
body: Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[new WidgetA(), new WidgetB(), new WidgetC()],
),
),
),
);
}
}
class MyInheritedWidget extends StatefulWidget {
MyInheritedWidget({
Key key,
this.child,
}) : super(key: key);
final Widget child;
@override
MyInheritedWidgetState createState() => new MyInheritedWidgetState();
static MyInheritedWidgetState of([BuildContext context]) {
return (context.inheritFromWidgetOfExactType(_MyInherited) as _MyInherited).data;
// 通過從 MyInheritedWidget 的 context 得到樹結構來返回第一個 MyInheritedWidgetState
}
}
class MyInheritedWidgetState extends State<MyInheritedWidget> {
int tempData = 0;
/// Helper method to add an Item
void addItem() {
setState(() {
tempData++;
});
}
@override
Widget build(BuildContext context) {
return new _MyInherited(
data: this,
child: widget.child,
);
}
}
class _MyInherited extends InheritedWidget {
_MyInherited({
Key key,
@required Widget child,
@required this.data,
}) : super(key: key, child: child);
final MyInheritedWidgetState data;
@override
bool updateShouldNotify(_MyInherited oldWidget) {
return true;
}
}
class WidgetA extends StatelessWidget {
@override
Widget build(BuildContext context) {
print('Widget A build');
final MyInheritedWidgetState state = MyInheritedWidget.of(context);
return Text('WidgetA data = ${state.tempData}');
}
}
class WidgetB extends StatelessWidget {
@override
Widget build(BuildContext context) {
print('Widget B build');
return Text('WidgetB');
}
}
class WidgetC extends StatefulWidget {
@override
_WidgetCState createState() => _WidgetCState();
}
class _WidgetCState extends State<WidgetC> {
@override
Widget build(BuildContext context) {
print('Widget C build');
final MyInheritedWidgetState state = MyInheritedWidget.of(context);
return RaisedButton(
child: Text("Click me"),
onPressed: () {
print('onPressed');
state.addItem();
},
);
}
}
複製程式碼
3. out demo 03,終極寫法
1. 程式碼結構
2. 效果圖
因為這個demo
的 Perfomance
介面展示不夠形象,就直接展示輸出log
檢視結果比較形象
可以發現 Widget A rebuild, Widget B Widget C no rebuild ,完美啊 ,寫到這裡已經要吐了
3. 程式碼
程式碼位置inheritedwidget_out_03.dart
/// 上移`Child`物件到`InheriteWidget`的`Parent Widget`
/// Widget A rebuild, Widget B Widget C no rebuild
class InheritedWidgetOut03 extends StatefulWidget {
@override
_InheritedWidgetOut03State createState() => new _InheritedWidgetOut03State();
}
class _InheritedWidgetOut03State extends State<InheritedWidgetOut03> {
@override
Widget build(BuildContext context) {
return new MyInheritedWidget(
child: new Scaffold(
appBar: new AppBar(
title: new Text('Title'),
),
body: Center(
child: new Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[new WidgetA(), new WidgetB(), new WidgetC()],
),
),
),
);
}
}
class MyInheritedWidget extends StatefulWidget {
MyInheritedWidget({
Key key,
this.child,
}) : super(key: key);
final Widget child;
@override
MyInheritedWidgetState createState() => new MyInheritedWidgetState();
static MyInheritedWidgetState of(
[BuildContext context, bool rebuild = true]) {
return (rebuild
? context.inheritFromWidgetOfExactType(_MyInherited) as _MyInherited
: context.ancestorWidgetOfExactType(_MyInherited) as _MyInherited)
.data;
// 通過從 MyInheritedWidget 的 context 得到樹結構來返回第一個 MyInheritedWidgetState
}
}
class MyInheritedWidgetState extends State<MyInheritedWidget> {
int tempData = 0;
/// Helper method to add an Item
void addItem() {
setState(() {
tempData++;
});
}
@override
Widget build(BuildContext context) {
return new _MyInherited(
data: this,
child: widget.child,
);
}
}
class _MyInherited extends InheritedWidget {
_MyInherited({
Key key,
@required Widget child,
@required this.data,
}) : super(key: key, child: child);
final MyInheritedWidgetState data;
@override
bool updateShouldNotify(_MyInherited oldWidget) {
return true;
}
}
class WidgetA extends StatelessWidget {
@override
Widget build(BuildContext context) {
print('Widget A build');
final MyInheritedWidgetState state = MyInheritedWidget.of(context);
return Text('WidgetA data = ${state.tempData}');
}
}
class WidgetB extends StatelessWidget {
@override
Widget build(BuildContext context) {
print('Widget B build');
return Text('WidgetB');
}
}
class WidgetC extends StatefulWidget {
@override
_WidgetCState createState() => _WidgetCState();
}
class _WidgetCState extends State<WidgetC> {
@override
Widget build(BuildContext context) {
print('Widget C build');
final MyInheritedWidgetState state = MyInheritedWidget.of(context, false);
return RaisedButton(
child: Text("Click me"),
onPressed: () {
print('onPressed');
state.addItem();
},
);
}
}
複製程式碼
7. 兩種解決方法,在原始碼中的應用
方法1 : 可以檢視TickerMode
這個類
方法2: 可以檢視 Theme
類
8. 參考文章
book.flutterchina.club/chapter7/in…