Flutter是一款響應式的UI框架,其中設計靈感很多來源于React.同React一樣,它將數據與視圖分離,由數據作為驅動去映射渲染視圖.so,也將widget分為Stateless widgets和Stateful widgets
- StatelessWidget: 是不可變的, 它是無狀態的,這意味著這些控件的屬性不能改變,是靜態的,就是我們常說的寫死的頁面.
- StatefulWidget: 持有的狀態,是動態頁面.它會隨狀態的改變而重新渲染自己本身.(StatefulWidget類本身是不變的,起作用的是State類,它在widget生命周期中始終存在的.)
實現一個有狀態的頁面如下:
// 1.繼承StatefulWidget,并實現其createState()方法,與自己的state綁定.
class HomePage extends StatefulWidget {
@override
_HomePageState createState() {
return new _HomePageState();
}
}
//2繼續State,并實現其build()方法創建自己UI視圖,通過調用setState方法去觸發視圖的渲染更新
class _HomePageState extends State<HomePage>{
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Column(
children: ContentLayout(),
),
)
}
}
實現一個擁有狀態的頁面至少需要實現其兩個類.你可能會意識到,隨著功能的增加,頁面的累積,會出現越來越多的狀態頁面,而且還會有多個頁面共享同一個狀態,導致代碼抒寫過于冗余和復雜.這時候,基于迫切的需要,狀態管理框架應運而生。
scoped_model
用于管理狀態的框架.官方文檔介紹中寫道,它可以輕松將數據模型從父級widget傳入它的children,并且當數據模型發生改變時,會自發的更新所有使用她的wigdet.現在來簡單講解下它的用法.
這里有三個主要用到的類:
- Model 如名,定義數據的類,將你要數據定義在一個類并繼承于它,類中有個notifyListeners(),用于刷新與它關聯的widgets.
import 'package:scoped_model/scoped_model.dart';
class CounterModel extends Model {
int _counter = 0;
int get counter => _counter;
void increment() {
// First, increment the counter
_counter++;
// Then notify all the listeners.
notifyListeners();
}
}
ScopedModel 它其實是個widget,繼承于StatelessWidget類.它主要接收兩個參數:model(數據模型)和child(會使用到這個數據模型對應的widget).
ScopedModelDescendant 它也繼承于StatelessWidget,使用此widget,其包含的子wigets可以找到對應的ScopedModel,它可以獲取與ScopedModel綁定的數據模型,且當數據模型發送改變時,它將自動重新構建渲染.說白了,它主要功能就是讓子頁面能夠獲取到model即數據~
class CounterApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new ScopedModel<CounterModel>(
model: new CounterModel(),
child: new Column(children: [
// Create a ScopedModelDescendant. This widget will get the
// CounterModel from the nearest ScopedModel<CounterModel>.
// It will hand that model to our builder method, and rebuild
// any time the CounterModel changes (i.e. after we
// `notifyListeners` in the Model).
new ScopedModelDescendant<CounterModel>(
builder: (context, child, model) => new Text('${model.counter}'),
),
new Text("Another widget that doesn't depend on the CounterModel")
])
);
}
}
當然還有另一種方法獲取到Model:
final countModel = ScopedModel.of<CountModel>(context);
然后這里我也有個比較疑惑的地方,就是當一個widet需要使用多個Model時,參考官方文檔講解(https://pub.dartlang.org/packages/scoped_model):
- Use multiple ScopedModelDescendant Widgets
- Use multiple ScopedModel.of calls. No need to manage subscriptions, Flutter takes care of all of that through the magic of InheritedWidgets.
class CombinedWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final username =
ScopedModel.of<UserModel>(context, rebuildOnChange: true).username;
final counter =
ScopedModel.of<CounterModel>(context, rebuildOnChange: true).counter;
return Text('$username tapped the button $counter times');
}
}
當是我在看ScopedModel 和ScopedModelDescendant 源碼時,類中并有提供接受多個model的構造方法. 然后參考https://juejin.im/post/5b97fa0d5188255c5546dcf8 , 是指Model 使用使用Mixin進行多繼承,但這必定帶來很多耦合
(如果有說的不當的,也請大佬賜教~共同交流,共同進步!)