一個界面是由衆多組件拼組而成。常常須要將一個組件進行封裝,但此時有一個問題,如何讓多個組件去共享一些值。bash
好比下面在一個_State中使用了WidgetA組件,傳入_incrementCounter自加的方法和_counter計數值。
WidgetA又是由下面若干個自定義的Widget組成。那麼問題來了,WidgetK點擊時如何讓WidgetE中的值+1?
一個最直接的方法就是經過構造函數將變量和函數一層層向下傳遞。你也許會說WTF,你好像在逗我笑?微信
將計數器的頁面分紅五個部分,分別用一個Widget來控制。app
WidgetA:控制視圖整體顯示 依賴WidgetB和WidgetF
WidgetB:控制視圖佈局排布 依賴WidgetC
WidgetC:控制視圖內容組成 依賴WidgetD
WidgetD:控制視圖計數器使用
WidgetF:控制視圖觸發計數
複製代碼
如今要讓WidgetF的點擊被WidgetD響應,下面是最笨的解決方案:構造傳參,一層層傳遞。雖然麻煩,但又不是不能用。less
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
@override
Widget build(BuildContext context) {
return WidgetA(_counter,_incrementCounter,widget.title);
}
void _incrementCounter() {
setState(() {
_counter++;
});
}
}
class WidgetA extends StatelessWidget {
WidgetA(this.counter,this.increment,this.title);
final int counter;
final VoidCallback increment;
final String title;
@override
Widget build(BuildContext context) {
var result= Scaffold(
appBar: AppBar(title: Text(title),),
body: WidgetB(counter),
floatingActionButton: WidgetF(increment),
);
return result;
}
}
class WidgetB extends StatelessWidget {
WidgetB(this.counter);
final int counter;
@override
Widget build(BuildContext context) {
var center= Center(
child: WidgetC(counter),
);
return center;
}
}
class WidgetC extends StatelessWidget {
WidgetC(this.counter);
final int counter;
@override
Widget build(BuildContext context) {
var column=Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('You have pushed the button this many times:',),
WidgetD(counter)
],
);
return column;
}
}
class WidgetD extends StatelessWidget {
WidgetD(this.counter);
final int counter;
@override
Widget build(BuildContext context) {
var text= Text('$counter', style: Theme.of(context).textTheme.display1,);
return text;
}
}
class WidgetF extends StatelessWidget {
WidgetF(this.increment);
final VoidCallback increment;
@override
Widget build(BuildContext context) {
var button= FloatingActionButton(
onPressed: increment,
tooltip: 'Increment',
child: Icon(Icons.add),
);
return button;
}
}
複製代碼
是否是感受很是麻煩呢? 如何處理這種狀況,能讓須要的參數不這麼跋山涉水?ide
這裏咱們使用一個InheritedWidget來提供數據和方法,讓她們共享與五個組件之中。就像下面這樣,將值存儲於一個InheritedWidget中,隨用隨取。這樣世界終於清靜了,不用構造傳值滿天飛。函數
/// 數據模型
class CountModel {
final int count;//計數器
final VoidCallback increment;//增加函數
const CountModel(this.count,this.increment);
}
class CountWidget extends InheritedWidget {
final CountModel model;
CountWidget({
Key key,
@required this.model,
@required Widget child,
}) : super(key: key, child: child);
static CountWidget of(BuildContext context) {//提供數據模型方法
return context.inheritFromWidgetOfExactType(CountWidget);
}
//是否重建widget就取決於數據是否相同
@override
bool updateShouldNotify(CountWidget oldWidget) {
return model.count != oldWidget.model.count;
}
}
複製代碼
再看一下如今每一個子組件的實現,就無需把須要的參數一層層往下傳。
若是你的封裝層級較深,InheritedWidget將是你數據傳遞的好幫手。佈局
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;
@override
Widget build(BuildContext context) {
return
CountWidget(child: WidgetA(widget.title),model: CountModel(_counter, _incrementCounter),);
}
void _incrementCounter() {
setState(() {
_counter++;
});
}
}
class WidgetA extends StatelessWidget {
WidgetA(this.title);
final String title;
@override
Widget build(BuildContext context) {
var result= Scaffold(
appBar: AppBar(title: Text(title),),
body: WidgetB(),
floatingActionButton: WidgetF(),
);
return result;
}
}
class WidgetB extends StatelessWidget {
@override
Widget build(BuildContext context) {
var center= Center(
child: WidgetC(),
);
return center;
}
}
class WidgetC extends StatelessWidget {
@override
Widget build(BuildContext context) {
var column=Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('You have pushed the button this many times:',),
WidgetD()
],
);
return column;
}
}
class WidgetD extends StatelessWidget {
@override
Widget build(BuildContext context) {
var counter= CountWidget.of(context).model.count;
var text= Text('$counter', style: Theme.of(context).textTheme.display1,);
return text;
}
}
class WidgetF extends StatelessWidget {
@override
Widget build(BuildContext context) {
var increment= CountWidget.of(context).model.increment;
var button= FloatingActionButton(
onPressed: increment,
tooltip: 'Increment',
child: Icon(Icons.add),
);
return button;
}
}
複製代碼
本文到此接近尾聲了,若是想快速嚐鮮Flutter,《Flutter七日》會是你的必備佳品;若是想細細探究它,那就跟隨個人腳步,完成一次Flutter之旅。
另外本人有一個Flutter微信交流羣,歡迎小夥伴加入,共同探討Flutter的問題,本人微信號:zdl1994328
,期待與你的交流與切磋。post
下一篇,將爲你帶來如何對當前代碼進行優化,讓狀態量更容易管理,敬請期待。優化