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示例的意思是试图简化情况的复杂性。

假设您要在小部件中显示和/或更改机组人员的姓名。在该应用本身您通常选择AircraftFleet(通过传递对窗口小部件List的索引),然后选择CrewMemberAircraft(由传递Map密钥),然后显示/改变NameCrewMember

最后,您的小部件将能够使用传入的Aircrafts索引和CrewMembers键来查看您所指的乘员组成员的名字。

我绝对愿意接受更好的架构和设计。

回答:

目前还不清楚是什么ABCD在你原来的问题主张。原来那是 模特

我目前的想法是,用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),

),

),

);

}

}

此应用可根据您ABCD类。

您的示例不使用代理,因为它仅使用D没有依赖关系的代理。但是您可以看到Provider通过以下示例正确连接了依赖项:

Consumer<A>(

builder: (context, a, _) => Text(a.b.c.d.runtimeType.toString())

),

它将打印出“ D”。

ChangeColor()因为没有打电话而没有工作notifyListeners()

无需在此之上使用有状态的小部件。

以上是 Flutter提供程序嵌套对象 的全部内容, 来源链接: utcz.com/qa/404341.html

回到顶部