class CounterModel with ChangeNotifier {
int _count = 0;
int get value => _count;
void increment() {
_count++;
notifyListeners();
}
}
void main() {
final counter = CounterModel();
runApp(
ChangeNotifierProvider.value(
value: counter,
child: MaterialApp(
home:FirstScreen()
),
),
);
}
class FirstScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final _counter = Provider.of<CounterModel>(context);
final textSize = Provider.of<int>(context).toDouble();
return Scaffold(
appBar: AppBar(
title: Text('FirstPage'),
),
body: Center(
child: Text(
'Value: ${_counter.value}',
style: TextStyle(fontSize: textSize),
),
),
floatingActionButton: FloatingActionButton(
onPressed: _counter.increment,
child: Icon(Icons.navigate_next),
),
);
}
如果你提供了多个状态可以使用MultiProvider
void main() {
final counter = CounterModel();
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (context)=>Counter()),
],
child: MaterialApp(
home:FirstScreen()
),
),
);
}
定义一个CounterModel,通过Provider组件注入组件树,子组件在build时可以通过Provider.of<CounterModel>(context)获取model,可以从model中获取数据,也可以直接调用model的方法(CounterModel.increment)修改数据。
这里用到的是ChangeNotifierProvider,它也是我们最常用的Provider。
除了ChangeNotifierProvider之外,Provider还提供了另外几种方式进行数据管理:
-
Provider
- 单纯共享数据给子组件,但是数据更新时不会通知子组件。
-
- 比起ChangeNotifierProvider区别主要是不会自动调用
ChangeNotifier.dispose
释放资源。一般不用。
- 比起ChangeNotifierProvider区别主要是不会自动调用
-
- 可以认为是ChangeNotifierProvider的特例,只监听一个数据的时候,使用ValueListenableProvider在修改数据时可以不用调用
notifyListeners()
。
- 可以认为是ChangeNotifierProvider的特例,只监听一个数据的时候,使用ValueListenableProvider在修改数据时可以不用调用
-
- 用于监听一个Stream
-
- 提供了一个 Future 给其子孙节点,并在 Future 完成时,通知依赖的子孙节点进行刷新
参考链接:https://segmentfault.com/a/1190000021157210?utm_source=tag-newest
Consumer
我们先看 floatingActionButton,使用了一个 Consumer 的情况。
Consumer 使用了 Builder模式,收到更新通知就会通过 builder 重新构建。Consumer<T> 代表了它要获取哪一个祖先中的 Model。
Consumer 的 builder 实际上就是一个 Function,它接收三个参数 (BuildContext context, T model, Widget child)。
context: context 就是 build 方法传进来的 BuildContext 。
T:T也很简单,就是获取到的最近一个祖先节点中的数据模型。
child:它用来构建那些与 Model 无关的部分,在多次运行 builder 中,child 不会进行重建。
然后它会返回一个通过这三个参数映射的 Widget 用于构建自身。
在这个浮动按钮的例子中,我们通过 Consumer 获取到了顶层的 CounterModel 实例。并在浮动按钮 onTap 的 callback 中调用其 increment 方法。
而且我们成功抽离出 Consumer 中不变的部分,也就是浮动按钮中心的 Icon 并将其作为 child 参数传入 builder 方法中。
还有 Consumer2, Consumer3,Consumer4,……
区别
我们来看 Consumer 的内部实现。
@override
Widget build(BuildContext context) {
return builder(
context,
Provider.of<T>(context),
child,
);
}
可以发现,Consumer 就是通过 Provider.of<T>(context) 来实现的。但是从实现来讲 Provider.of<T>(context) 比 Consumer 简单好用太多,为啥我要搞得那么复杂捏。
实际上 Consumer 非常有用,它的经典之处在于能够在复杂项目中,极大地缩小你的控件刷新范围。Provider.of<T>(context) 将会把调用了该方法的 context 作为听众,并在 notifyListeners 的时候通知其刷新。
class FirstScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Consumer<CounterProvider>(builder: (context, counterModel, child) {
return Scaffold(
appBar: AppBar(
title: Text('FirstPage'),
),
body: Center(
child: Text(
'Value: ${counterModel.value}',
),
),
floatingActionButton: FloatingActionButon(
onPressed: counterModel.increment,
child: Icon(Icons.navigate_next),
),
);
});
}
}
原文链接:https://blog.csdn.net/lpfasd123/java/article/details/101573980
网友评论