简介
ScopedModel
允许将数据模型从父Widget传递到后代,会在模型更新时重新渲染使用该模型的所有子项。
安装依赖
在pubspec.yml
中添加scoped_model
的依赖。
scoped_model: ^1.0.1
创建模型
1 | class CounterModel extends Model {
|
2 | int _count = 0;
|
3 | int get count => _count;
|
4 | void increment() {
|
5 | _count++;
|
6 | notifyListeners();
|
7 | }
|
8 | void reduce() {
|
9 | _count--;
|
10 | notifyListeners();
|
11 | }
|
12 | static CounterModel of(BuildContext context) => ScopedModel.of<CounterModel>(context);
|
13 | }
|
- 让我们自定义的
CounterModel
继承Model
.
- 当调用
increment
方法时改变了数据,然后notifyListeners
会通知所有用到该模型的子项更新状态
将MaterialApp用ScopedModel包装起来
1 | class MyApp extends StatelessWidget {
|
2 | @override
|
3 | Widget build(BuildContext context) {
|
4 | return ScopedModel<CounterModel>(
|
5 | model: CounterModel(),
|
6 | child: MaterialApp(
|
7 | theme: ThemeData(
|
8 | primarySwatch: Colors.yellow,
|
9 | ),
|
10 | debugShowCheckedModeBanner: false,
|
11 | home: ScopedModelDemo(),
|
12 | ),
|
13 | );
|
14 | }
|
15 | }
|
- ScopedModel 接受两个参数:model 和 child .
- model 我们传入 CounterModel 实例
在子页面获取Model
1 | class ScopedModelDemo extends StatelessWidget {
|
2 | @override
|
3 | Widget build(BuildContext context) {
|
4 | return Scaffold(
|
5 | appBar: AppBar(
|
6 | title: Text('ScopedModelDemo'),
|
7 | elevation: 0.0,
|
8 | ),
|
9 | body: ScopedModelDemoHome(),
|
10 | floatingActionButton: FloatingActionButton(
|
11 | onPressed: () {
|
12 | Navigator.of(context)
|
13 | .push(MaterialPageRoute(builder: (context) => SecondPage()));
|
14 | },
|
15 | tooltip: 'Increment',
|
16 | child: Icon(Icons.open_in_new),
|
17 | ),
|
18 | );
|
19 | }
|
20 | }
|
21 |
|
22 | class ScopedModelDemoHome extends StatefulWidget {
|
23 | @override
|
24 | _ScopedModelDemoHomeState createState() => _ScopedModelDemoHomeState();
|
25 | }
|
26 |
|
27 | class _ScopedModelDemoHomeState extends State<ScopedModelDemoHome> {
|
28 | @override
|
29 | Widget build(BuildContext context) {
|
30 | return Center(
|
31 | child: Column(
|
32 | mainAxisAlignment: MainAxisAlignment.center,
|
33 | children: <Widget>[
|
34 | ScopedModelDescendant<CounterModel>(
|
35 | rebuildOnChange: false,
|
36 | builder: (context, child, model) {
|
37 | print('add');
|
38 | return FlatButton(
|
39 | onPressed: model.increment,
|
40 | child: Icon(Icons.add),
|
41 | color: Colors.blue,
|
42 | );
|
43 | },
|
44 | ),
|
45 | ScopedModelDescendant<CounterModel>(
|
46 | builder: (context, child, model) {
|
47 | print('Text ---${model.count}');
|
48 | return Text(
|
49 | model.count.toString(),
|
50 | );
|
51 | },
|
52 | ),
|
53 | ScopedModelDescendant<CounterModel>(
|
54 | rebuildOnChange: false,
|
55 | builder: (context, child, model) {
|
56 | print('remove');
|
57 | return FlatButton(
|
58 | onPressed: model.reduce,
|
59 | child: Icon(Icons.remove),
|
60 | color: Colors.blue,
|
61 | );
|
62 | },
|
63 | ),
|
64 | ],
|
65 | ),
|
66 | );
|
67 | }
|
68 | }
|
69 |
|
70 | class SecondPage extends StatefulWidget {
|
71 | @override
|
72 | _SecondPageState createState() => _SecondPageState();
|
73 | }
|
74 |
|
75 | class _SecondPageState extends State<SecondPage> {
|
76 | @override
|
77 | Widget build(BuildContext context) {
|
78 | final count =
|
79 | ScopedModel.of<CounterModel>(context, rebuildOnChange: true).count;
|
80 | final counterModel =
|
81 | ScopedModel.of<CounterModel>(context, rebuildOnChange: false);
|
82 |
|
83 | return Scaffold(
|
84 | appBar: AppBar(
|
85 | title: Text('SecondPage'),
|
86 | elevation: 0.0,
|
87 | ),
|
88 | body: Center(
|
89 | child: Column(
|
90 | mainAxisAlignment: MainAxisAlignment.center,
|
91 | children: <Widget>[
|
92 | Text('$count'),
|
93 | FlatButton(
|
94 | onPressed: counterModel.reduce,
|
95 | child: Icon(Icons.remove),
|
96 | color: Colors.blue,
|
97 | )
|
98 | ],
|
99 | ),
|
100 | ),
|
101 | floatingActionButton: FloatingActionButton(
|
102 | onPressed: (){
|
103 | counterModel.increment();
|
104 | },
|
105 | tooltip: 'Increment',
|
106 | child: new Icon(Icons.add),
|
107 | ),
|
108 | );
|
109 | }
|
110 | }
|
Scoped_model 提供了两种获取model的方式。
第一种:ScopedModelDescendant.
rebuildOnChange用来控制当该状态发生变化时,是否rebuild。
ScopedModelDescendant<CounterModel>(
rebuildOnChange: true,
builder: (context, child, model) {
print('Text ---${model.count}');
return Text(
model.count.toString(),
);
},
),
第二章:ScopedModel.of
需要在Model中重写of方法。
static CounterModel of(BuildContext context) => ScopedModel.of(context);
然后直接通过CounterModel获取model实例
final counterModel = ScopedModel.of(context, rebuildOnChange: false);
监听多个model
通过Mixin进行混入。
class CounterModel extends Model with ClickModel{}
虽然有效果,但是编辑器提示错误:说不能进行 Mixin。这个问题待解决
The class ‘ClickModel’ can’t be used as a mixin because it extends a class other than Object.