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进行多继承,但这必定带来很多耦合
(如果有说的不当的,也请大佬赐教~共同交流,共同进步!)
网友评论