在应用开发过程中数据传递,flutter提供 InheritedWidget 以及多种 provider, 各有差异从从使用习惯上面 这边主要介绍以下两种:
- InheritedWidget
- provider (ChangeNotifier)
InheritedWidget:
提供一种 从上而下 的数据提供 (而且子节点需要 Widget 包裹); 且单向。切记只能由上而下的刷新数据;不能做到 子节点 变数据 而刷新的情况!常用于 静态数据的存储;不会改变的常量保存; 或者子节点只作为 静态展示的数据,父节点提供元数据。子节点展示数据 不参与动态更新交互
效果如下:
脚本结构:
inherited_datum.dart
import 'package:flutter/cupertino.dart'; class InheritedDatum extends InheritedWidget { final int count; const InheritedDatum({Key? key, required child, required this.count}) : super(key: key, child: child); static InheritedDatum? of(BuildContext context) { return context.dependOnInheritedWidgetOfExactType<InheritedDatum>(); } ///**子组件不能 通过调用该方法 实现子组件刷新 updateCount(int count) { count = count; } @override bool updateShouldNotify(covariant InheritedDatum oldWidget) { // TODO: implement updateShouldNotify return oldWidget.count != count; } }
widget_child0.dart
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'inherited_datum.dart'; class WidgetChild0 extends StatelessWidget { const WidgetChild0({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Container( color: Colors.blue, height: 40, width: 80, child: Center( child: Text( '${InheritedDatum.of(context)?.count}', style: TextStyle(color: Colors.white), ), ), ); } }
widget_child1.dart
import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'inherited_datum.dart'; class WidgetChild1 extends StatelessWidget { const WidgetChild1({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Container( color: Colors.blue, height: 40, width: 80, child: Center( child: Text( '${InheritedDatum.of(context)?.count}', style: TextStyle(color: Colors.white), ), ), ); } }
入口:main.dart
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( // Here we take the value from the MyHomePage object that was created by // the App.build method, and use it to set our appbar title. title: Text(widget.title), ), body: Center( child: InheritedDatum( count: _counter, child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, // children: const [], children: const [WidgetChild0(), WidgetChild1()], ), ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: const Icon(Icons.add), ), // This trailing comma makes auto-formatting nicer for build methods. ); }
InheritedWidget 使用注意细节:
1. 必须是 子组件:平行的都不行:
2. 子组件获取 InheritedWidget 中的数据 通过:
InheritedDatum.of(context)?.count
3. 子组件不能仅 通过调用 InheritedWidget 中的方便实现 子组件刷新
小结:
InheritedWidget 的适用场景:子组件共享 父组件中的数据;但不具备 修改更新 父组件中数据的 能力!下面介绍的 ChangeNotifier 则具备 上下 更新数据的能力
provider 数据传递
provider是基于InheritedWidget 的包装 ;为了在Provider中进行数据共享首先我们需要为其定义一个数据模型,为了能够订阅数据的状态通常会让这个数据模型来继承
ChangeNotifier,达到更新的目的; 使用前先导入:
provider: ^6.0.5dependencies: flutter: sdk: flutter provider: ^6.0.5
之前的总结: https://johns.blog.csdn.net/article/details/122139508
需要在父节点中使用以下 组件来完成 子组件的更新:按照自己 更新逻辑的 复杂度。按照实际需要选取适合的 模型
- ChangeNotifierProvider
- ProxyProvider
- MultiProvider
- Consumer
效果如下:
父组件 和 子组件都可以 实现对数据的更新
脚本结构:
counter.dart
import 'package:flutter/cupertino.dart'; class Counter with ChangeNotifier { int _count = 0; int get count => _count; void increment() { _count++; notifyListeners(); } void set(int count) { _count = count; notifyListeners(); } }
widget_child0.dart
import 'package:untitled1/counter.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class WidgetChild0 extends StatelessWidget { const WidgetChild0({Key? key}) : super(key: key); Widget build(BuildContext context) { return Container( color: Colors.blue, height: 40, width: 80, child: GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { context.read<Counter>().set(0); print('WidgetChild0'); }, child: Center( child: Text( '${context.watch<Counter>().count}', style: TextStyle(color: Colors.white), ), ), ), ); } }
widget_child1.dart
import 'package:untitled1/counter.dart'; import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; class WidgetChild1 extends StatelessWidget { const WidgetChild1({Key? key}) : super(key: key); Widget build(BuildContext context) { return Container( color: Colors.blue, height: 40, width: 80, child: GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { context.read<Counter>().set(1); print('WidgetChild1'); }, child: Center( child: Text( '${context.watch<Counter>().count}', style: TextStyle(color: Colors.white), ), ), ), ); } }
main.dart
class MyApp extends StatelessWidget { const MyApp({super.key}); // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: ChangeNotifierProvider( create: (_) => Counter(), child: const MyHomePage(title: 'Flutter Demo Home Page'), ), //home: const MyHomePage(title: 'Flutter Demo Home Page'), ); } }
Widget build(BuildContext context) { return Scaffold( appBar: AppBar( // Here we take the value from the MyHomePage object that was created by // the App.build method, and use it to set our appbar title. title: Text(widget.title), ), body: Center( child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, // children: const [], children: const [WidgetChild0(), WidgetChild1()], ), ), floatingActionButton: FloatingActionButton( onPressed: () { context.read<Counter>().increment(); }, tooltip: 'Increment', child: const Icon(Icons.add), ), // This trailing comma makes auto-formatting nicer for build methods. ); }
provide 使用注意细节:
也是共享的数据需要放在 父节点中; 再共有的父节点中 都可以对 数据进行修改更新; 实现双向动态数据: 调用
notifyListeners其中 MultiProvider,Consumer 适合多组 ChangeNotifier ;以实现解耦操作;基本用法和ChangeNotifierProvider 相同;详细可参考:https://johns.blog.csdn.net/article/details/122139508https://johns.blog.csdn.net/article/details/122139508