gpt4 book ai didi

flutter - 嵌套Provider的notifyListeners()没有更新UI

转载 作者:行者123 更新时间:2023-12-02 21:14:13 28 4
gpt4 key购买 nike

我正在使用provider flutter 包。

我有一个主列表,主列表的每个项目都有一个子列表。我可以将项目添加到主列表并且它正在工作,但每次我向子列表添加项目时,用户界面都不会更新。运行代码并添加一些项目并打开它们,然后在其中添加一些项目(这是子列表),您将看到您不会看到任何更新,但如果您最小化键盘,UI 将得到更新。也许是因为我正在使用 Provider.of<Collection>(context)访问子列表的对象和 notifyListeners() CityName的类无法运行findById(id)这是我能想到的。

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider.value(
value: Collection(),
),
ChangeNotifierProvider.value(
value: CityName(),
)
],
child: MaterialApp(
home: MyHomePage(),
),
);
}
}

class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
final _textEditingController = TextEditingController();

@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: ListView(
children: Provider.of<Collection>(context)
.cityNameCollection
.map((collection) {
return CollectionCard(collection.title, collection.id);
}).toList()),
),
Container(
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: TextField(
controller: _textEditingController,
autofocus: true,
),
),
FlatButton(
onPressed: () {
Provider.of<Collection>(context)
.addCollection(_textEditingController.text);
_textEditingController.clear();
},
child: Text(
'ADD',
),
),
],
),
),
]),
);
}
}

class CollectionCard extends StatelessWidget {
final String title;
final String id;

CollectionCard(this.title, this.id);
@override
Widget build(BuildContext context) {
return GestureDetector(
child: Card(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 20),
child: Text(title),
),
),
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => CityNamesList(id),
),
);
},
);
}
}

class CityNamesList extends StatelessWidget {
final String id;
CityNamesList(this.id);
final _textEditingController = TextEditingController();

@override
Widget build(BuildContext context) {
final item = Provider.of<Collection>(context).findById(id);

return Scaffold(
appBar: AppBar(
title: Text(item.title),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: ListView(
children: item.names.map((name) {
return ListTile(
title: Text(name),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () {
item.removeName(name);
},
),
);
}).toList()),
),
Container(
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: TextField(
controller: _textEditingController,
autofocus: true,
),
),
FlatButton(
onPressed: () {
item.addName(_textEditingController.text);
_textEditingController.clear();
},
child: Text(
'ADD',
),
),
],
),
),
],
),
);
}
}

class Collection with ChangeNotifier {
List<CityName> cityNameCollection = [];

void addCollection(value) {
cityNameCollection
.add(CityName(title: value, id: DateTime.now().toString()));
notifyListeners();
}

CityName findById(id) {
return cityNameCollection.firstWhere((a) => a.id == id);
}
}

class CityName with ChangeNotifier {
String title;
String id;
List<String> names = [];

CityName({this.title, this.id});

void addName(value) {
names.add(value);
notifyListeners();
}

void removeName(value) {
names.remove(value);
notifyListeners();
}
}

最佳答案

这里有几个问题

1) 您正在 ChangeNotifierProvider.value 内创建 Collection(),这可能会导致重新创建它(不仅是现在,而且在代码发生一些更改之后)。相反,将 ChangeNotifierProviderbuilder 一起使用,这将只创建一次值

2) 您对 CityName 使用单个 ChangeNotifierProvider,而可以有多个 CityName 实例。因此,所有提供商将始终为您提供相同的实例,而不是引用 CityName 的特定实例

3)传递collection.id然后通过id查找它是不必要的,并且会使代码复杂化。只需传递集合实例本身

4) CityNamesList 未提供特定的 CityName,而是从 Collection 提供者获取。在这种情况下,UI 将不会重建,因为它不会监听 CityNamesList 更改。实际上,它监听 Collection 更改,但 Collection 不知道其项目何时更改,因为没有人调用 notifyListeners() 位于CityName@addName内的Collection

5) 最后,CityName 的构造函数字段是可选的(不是必需的),它允许创建虚拟实例并导致错误

这是一个如何解决此问题的示例(为简单起见,没有 removeName)

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
builder: (context) => Collection(),
child: MaterialApp(
home: MyHomePage(),
),
);
}
}

class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
final _textEditingController = TextEditingController();

@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: ListView(
children: Provider.of<Collection>(context)
.cityNameCollection
.map((item) => CollectionCard(item))
.toList(),
),
),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: TextField(
controller: _textEditingController,
autofocus: true,
),
),
FlatButton(
onPressed: () {
Provider.of<Collection>(context)
.addCollection(_textEditingController.text);
_textEditingController.clear();
},
child: Text('ADD'),
),
],
),
],
),
);
}
}

class CollectionCard extends StatelessWidget {
final CityName item;

CollectionCard(this.item);

@override
Widget build(BuildContext context) {
return GestureDetector(
child: Card(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 20),
child: Text(item.title),
),
),
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) {
return ChangeNotifierProvider.value(
value: item,
child: CityNamesList(),
);
},
),
);
},
);
}
}

class CityNamesList extends StatelessWidget {
final _textEditingController = TextEditingController();

@override
Widget build(BuildContext context) {
final item = Provider.of<CityName>(context);

return Scaffold(
appBar: AppBar(
title: Text(item.title),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: ListView(
children: item.names.map((name) {
return ListTile(
title: Text(name),
);
}).toList(),
),
),
Container(
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Expanded(
child: TextField(
controller: _textEditingController,
autofocus: true,
),
),
FlatButton(
onPressed: () {
item.addName(_textEditingController.text);
_textEditingController.clear();
},
child: Text('ADD'),
),
],
),
),
],
),
);
}
}

class Collection with ChangeNotifier {
List<CityName> cityNameCollection = [];

void addCollection(String value) {
cityNameCollection.add(CityName(title: value));
notifyListeners();
}
}

class CityName with ChangeNotifier {
String title;
List<String> names = [];

CityName({@required this.title});

void addName(value) {
names.add(value);
notifyListeners();
}
}

关于flutter - 嵌套Provider的notifyListeners()没有更新UI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58106034/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com