簡單一點說html
- inhertedwidget 是一個widget,跟其餘widget不同的地方是,他能夠在他所持有的child中共享本身的數據。如Theme。
- 應用場景:app的複雜度愈來愈大,對於數據之間的傳遞,若是都是根據dic或者model做爲widget內部的參數傳遞,是不友好的方式。正常的想法,此時應該有個數據中心,或eventbus,用於數據傳遞和取用,而在flutter中是inhertwidget
- 實現: 內部實現數據更新,自動通知的方式,從而自動刷新界面
- 寫法: 見下面例子
對於趕時間的同窗看到這裏就能夠回去搬磚了。下面留給還有五分鐘時間瀏覽的同窗。數據庫
google 在flutter widget of the week
中介紹 inheritedwidget
, 短短的兩個簡短的視頻,讓人看到了flutter的用心,外語通常的我也能把概念看得個大概。可是對於真正使用其上手開發的同窗總以爲離實際開發距離有點遠,仍是得編寫一下例子才能理解更深一點。api
做爲一名高效的搬磚工,先看看它說了啥bash
當應用變得更大時,小部件樹,變得更復雜,傳遞和訪問數據,會變得很麻煩。 若是你有四個或五個小部件一個接一個地嵌套, 而且您須要從頂部獲取一些數據。將它添加到全部這些構造函數中,以及全部這些構建方法。網絡
然而我只是想到達widget來獲取數據。 不想一級一級傳遞數據。怎麼辦?幸運的是,有一個小部件類型容許這樣。 它叫作InheritedWidget。app
class FrogColor extends InheritedWidget {
const FrogColor({
Key key,
@required this.color,
@required Widget child,
}) : assert(color != null),
assert(child != null),
super(key: key, child: child);
final Color color;
static FrogColor of(BuildContext context) {
return context.inheritFromWidgetOfExactType(FrogColor) as FrogColor;
}
@override
bool updateShouldNotify(FrogColor old) => color != old.color;
}
複製代碼
class TestWidgetA extends StatelessWidget {
@override
Widget build(BuildContext context) {
final inheritedContext = FrogColor.of(context);
return new Padding(
padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
child: Container(
color: inheritedContext.color,
height: 100,
width: 100,
child: Text('第一個widget'),
));
}
}
class TestWidgetB extends StatelessWidget {
@override
Widget build(BuildContext context) {
final inheritedContext = FrogColor.of(context);
return new Padding(
padding: const EdgeInsets.only(left: 10.0, top: 10.0, right: 10.0),
child: Container(
color: inheritedContext.color,
height: 50,
width: 50,
child: Text('第二個widget'),
));
}
}
複製代碼
class TestWidgetC extends StatefulWidget {
TestWidgetC({Key key}) : super(key: key);
_TestWidgetCState createState() => _TestWidgetCState();
}
class _TestWidgetCState extends State<TestWidgetC> {
@override
Widget build(BuildContext context) {
final inheritedContext = FrogColor.of(context);
// print(" 重建c CCC ");
return Container(
child: Container(
color: inheritedContext.color,
height: 200,
width: 200,
child: prefix0.Column(
children: <Widget>[
Text("第三個widget"),
],
),
));
}
@override
void didChangeDependencies() {
print(" 更改依賴 CCC ");
super.didChangeDependencies();
}
}
複製代碼
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
Color color = Color.fromARGB(0, 0xff, 0xdd, 0xdd);
Color color2 = Color.fromARGB(0, 0xff, 0xdd, 0xdd);
void _incrementCounter() {
setState(() {
_counter = (_counter + 20) % 255;
Color color = Color.fromARGB(_counter, 0xff, 0xdd, 0xdd);
this.color = color;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
new FrogColor(
color: this.color,
color2: this.color2,
child: Column(
children: <Widget>[
new TestWidgetA(),
new TestWidgetB(),
new TestWidgetC()
],
),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
複製代碼
本段代碼實現了點擊+號,數字增長,而且兩個widget的顏色加深less
效果圖以下ide
它爲您調用InheritWidget的精確類型方法。函數
static FrogColor of(BuildContext context) {
return context.inheritFromWidgetOfExactType(FrogColor) as FrogColor;
}
複製代碼
例子中FrogColor 裏面的color就是一個final類型,不能夠改變ui
只能替換InheritedWidget的字段,經過重建
整個widget 樹。 這個很重要!!! 只是意味着它沒法從新分配
。 可是並不意味着它不能在內部改變。
inhertedwidget改變了就會觸發,didChangeDependencies,對於耗時操做的業務如網絡請求來講能夠放置這裏。
從上例中能夠作個試驗,在widgetC中移除 FrogColor.of(context)
這句話,能夠看到,顏色很差隨着按鈕點擊變色,另外也不會調用didChangeDependencies
這個方法了。可是widgetc仍是會走build方法。
能夠印證兩點,widget會重建,可是state不會重建,didChangeDespendice方法調用的時機是其依賴的上下文內容改變。
Theme其實是一種InheritedWidget。 Scaffold,Focus Scope等等也是如此。
附加服務對象到InheritedWidget。 如開發數據庫的包裝器
Web API的代理或資產提供者。 服務對象能夠有本身的內部狀態。 它能夠啓動網絡呼叫,任何事情。
繼承自Inhertedwidget,其值能夠是被監聽的,而且只要值發送通知就會通知依賴者。
使用場景有 ChangeNotifier
或ValueNotifier
abstract class InheritedNotifier<T extends Listenable> extends InheritedWidget {
const InheritedNotifier({
Key key,
this.notifier,
@required Widget child,
}) : assert(child != null),
super(key: key, child: child);
@override
bool updateShouldNotify(InheritedNotifier<T> oldWidget) {
return oldWidget.notifier != notifier;
}
@override
_InheritedNotifierElement<T> createElement() => _InheritedNotifierElement<T>(this);
}
複製代碼
繼承自 Inertedwidget的,容許客戶端訂閱值的子部分的更改。
就比InertedWidget多了一個必要方法updateShouldNotifyDependent
,表示能夠根據,部份內容的改變發送依賴變動通知。
class ABModel extends InheritedModel<String> {
ABModel({this.a, this.b, Widget child}) : super(child: child);
final int a;
final int b;
@override
bool updateShouldNotify(ABModel old) {
return a != old.a || b != old.b;
}
@override
bool updateShouldNotifyDependent(ABModel old, Set<String> aspects) {
return (a != old.a && aspects.contains('a')) ||
(b != old.b && aspects.contains('b'));
}
// ...
}
複製代碼
一圖說明
參考