Flutter提供程序嵌套对象
我正在使用提供程序包来管理Flutter应用程序中的状态。我开始嵌套对象时遇到问题。
一个非常简单的示例:父A的子类型为B,子的类型为C,子类型为D。在子D中,我要管理颜色属性。下面的代码示例:
import 'package:flutter/material.dart';class A with ChangeNotifier
{
A() {_b = B();}
B _b;
B get b => _b;
set b(B value)
{
_b = value;
notifyListeners();
}
}
class B with ChangeNotifier
{
B() {_c = C();}
C _c;
C get c => _c;
set c(C value)
{
_c = value;
notifyListeners();
}
}
class C with ChangeNotifier
{
C() {_d = D();}
D _d;
D get d => _d;
set d(D value)
{
_d = value;
notifyListeners();
}
}
class D with ChangeNotifier
{
int _ColorIndex = 0;
final List<Color> _ColorList = [
Colors.black,
Colors.blue,
Colors.green,
Colors.purpleAccent
];
D()
{
_color = Colors.red;
}
void ChangeColor()
{
if(_ColorIndex < _ColorList.length - 1)
{
_ColorIndex++;
}
else
{
_ColorIndex = 0;
}
color = _ColorList[_ColorIndex];
}
Color _color;
Color get color => _color;
set color(Color value)
{
_color = value;
notifyListeners();
}
}
现在我的 (正在管理我的Placeholder()
小部件)包含以下内容:
import 'package:flutter/material.dart';import 'package:provider/provider.dart';
import 'package:provider_example/NestedObjects.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget
{
@override
Widget build(BuildContext context)
{
return MaterialApp(
home: ChangeNotifierProvider<A>(
builder: (context) => A(),
child: MyHomePage()
),
);
}
}
class MyHomePage extends StatefulWidget
{
@override
State createState()
{
return _MyHomePageState();
}
}
class _MyHomePageState extends State<MyHomePage>
{
@override
Widget build(BuildContext context)
{
A a = Provider.of<A>(context);
B b = a.b;
C c = b.c;
D d = c.d;
return Scaffold(
body: Center(
child: Column(
children: <Widget>[
Text(
'Current selected Color',
),
Placeholder(color: d.color,),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => ButtonPressed(context),
tooltip: 'Increment',
child: Icon(Icons.arrow_forward),
),
);
}
void ButtonPressed(BuildContext aContext)
{
A a = Provider.of<A>(context);
B b = a.b;
C c = b.c;
D d = c.d;
d.ChangeColor();
}
}
由上述可知,该 的颜色属性被限定 的颜色属性“ (A -> B -> C ->
D.color)。上面的代码经过了极大简化,但确实显示了我遇到的问题。
:如何将 子D 的color属性分配给小部件,以便在更新 子D
的属性时,它也自动更新小部件(使用notifyListeners()
,而不是setState()
)。
我使用了 , , 和
,所有这些都给我相同的结果。重申一下,对象不能分离,它必须具有父子关系。
更复杂的示例:
import 'dart:ui';enum Manufacturer
{
Airbus, Boeing, Embraer;
}
class Fleet
{
List<Aircraft> Aircrafts;
}
class Aircraft
{
Manufacturer AircraftManufacturer;
double EmptyWeight;
double Length;
List<Seat> Seats;
Map<int,CrewMember> CrewMembers;
}
class CrewMember
{
String Name;
String Surname;
}
class Seat
{
int Row;
Color SeatColor;
}
上面的代码是真实示例的简化版本。可以想象,兔子洞会越来越深。因此,A
直通D
示例的意思是试图简化情况的复杂性。
假设您要在小部件中显示和/或更改机组人员的姓名。在该应用本身您通常选择Aircraft
从Fleet
(通过传递对窗口小部件List
的索引),然后选择CrewMember
从Aircraft
(由传递Map
密钥),然后显示/改变Name
的CrewMember
。
最后,您的小部件将能够使用传入的Aircrafts
索引和CrewMembers
键来查看您所指的乘员组成员的名字。
我绝对愿意接受更好的架构和设计。
回答:
目前还不清楚是什么A
,B
,C
和D
在你原来的问题主张。原来那是 模特 。
我目前的想法是,用MultiProvider
/ 包装您的应用程序 ProxyProvider
以提供 服务 ,而不是模型。
不知道如何加载数据(如果有的话),但是我假定了一种异步获取船队的服务。如果您的数据是通过零件/模型通过不同的服务加载的(而不是一次全部)加载的,则可以将其添加到中,MultiProvider
并在需要加载更多数据时将其插入适当的小部件中。
下面的示例是完整的功能。为了简单起见,并且由于您以更新name
为例进行了询问,所以我仅设置了该属性设置器notifyListeners()
。
import 'package:flutter/material.dart';import 'package:provider/provider.dart';
main() {
runApp(
MultiProvider(
providers: [Provider.value(value: Service())],
child: MyApp()
)
);
}
class MyApp extends StatelessWidget {
@override
Widget build(context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: Consumer<Service>(
builder: (context, service, _) {
return FutureBuilder<Fleet>(
future: service.getFleet(), // might want to memoize this future
builder: (context, snapshot) {
if (snapshot.hasData) {
final member = snapshot.data.aircrafts[0].crewMembers[1];
return ShowCrewWidget(member);
} else {
return CircularProgressIndicator();
}
}
);
}
),
),
),
);
}
}
class ShowCrewWidget extends StatelessWidget {
ShowCrewWidget(this._member);
final CrewMember _member;
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<CrewMember>(
create: (_) => _member,
child: Consumer<CrewMember>(
builder: (_, model, __) {
return GestureDetector(
onDoubleTap: () => model.name = 'Peter',
child: Text(model.name)
);
},
),
);
}
}
enum Manufacturer {
Airbus, Boeing, Embraer
}
class Fleet extends ChangeNotifier {
List<Aircraft> aircrafts = [];
}
class Aircraft extends ChangeNotifier {
Manufacturer aircraftManufacturer;
double emptyWeight;
double length;
List<Seat> seats;
Map<int,CrewMember> crewMembers;
}
class CrewMember extends ChangeNotifier {
CrewMember(this._name);
String _name;
String surname;
String get name => _name;
set name(String value) {
_name = value;
notifyListeners();
}
}
class Seat extends ChangeNotifier {
int row;
Color seatColor;
}
class Service {
Future<Fleet> getFleet() {
final c1 = CrewMember('Mary');
final c2 = CrewMember('John');
final a1 = Aircraft()..crewMembers = { 0: c1, 1: c2 };
final f1 = Fleet()..aircrafts.add(a1);
return Future.delayed(Duration(seconds: 2), () => f1);
}
}
运行该应用程序,等待2秒钟以加载数据,然后您将在该地图中看到ID为1的机组人员“约翰”。然后双击文本,它应该更新为“ Peter”。
如您所见,我正在使用服务的顶级注册(Provider.value(value:
Service()))和模型的本地注册(ChangeNotifierProvider<CrewMember>(create: ...)
)。
我认为这种架构(具有合理数量的模型)应该是可行的。
关于本地级别的提供程序,我觉得它有点冗长,但是可能有一些方法可以使它更简短。同样,为模型提供一些代码生成库,这些模型具有用setter通知更改的功能。
(您有C#背景吗?我已将您的类固定为符合Dart语法。)
让我知道这是否适合您。
如果要使用提供程序,则必须使用提供程序构建依赖关系图。
(您可以选择构造函数注入,而不是setter注入)
这有效:
main() { runApp(MultiProvider(
providers: [
ChangeNotifierProvider<D>(create: (_) => D()),
ChangeNotifierProxyProvider<D, C>(
create: (_) => C(),
update: (_, d, c) => c..d=d
),
ChangeNotifierProxyProvider<C, B>(
create: (_) => B(),
update: (_, c, b) => b..c=c
),
ChangeNotifierProxyProvider<B, A>(
create: (_) => A(),
update: (_, b, a) => a..b=b
),
],
child: MyApp(),
));
}
class MyApp extends StatelessWidget {
@override
Widget build(context) {
return MaterialApp(
title: 'My Flutter App',
home: Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Current selected Color',
),
Consumer<D>(
builder: (context, d, _) => Placeholder(color: d.color)
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => Provider.of<D>(context, listen: false).color = Colors.black,
tooltip: 'Increment',
child: Icon(Icons.arrow_forward),
),
),
);
}
}
此应用可根据您A
,B
,C
和D
类。
您的示例不使用代理,因为它仅使用D
没有依赖关系的代理。但是您可以看到Provider通过以下示例正确连接了依赖项:
Consumer<A>( builder: (context, a, _) => Text(a.b.c.d.runtimeType.toString())
),
它将打印出“ D”。
ChangeColor()
因为没有打电话而没有工作notifyListeners()
。
无需在此之上使用有状态的小部件。
以上是 Flutter提供程序嵌套对象 的全部内容, 来源链接: utcz.com/qa/404341.html