我正在使用provider Flutter软件包。
我有一个主列表,主列表的每个项目都有一个子列表。我可以将项目添加到主列表中,并且可以正常工作,但是每次我向子列表添加内容时,UI都不会更新。运行代码并添加一些项目,然后打开它们,然后在其中添加一些项目(这是子列表),您将看到看不到任何更新,但是如果最小化键盘,则UI将会更新。可能是因为我正在使用Provider.of<Collection>(context)
访问子列表的对象,而notifyListeners()
类的CityName
无法运行findById(id)
,这是我能想到的。 / p>
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();
}
}
答案 0 :(得分:1)
这里有几个问题
1)您正在Collection()
内创建ChangeNotifierProvider.value
,这可能导致重新创建它(不仅是现在,而且在代码进行一些更改之后)。而是将ChangeNotifierProvider
与builder
一起使用,这将只创建一次值
2)您为ChangeNotifierProvider
使用了单个 CityName
,但可以有多个CityName
实例。因此,所有提供程序都不会始终引用CityName
的特定实例
3)不需要传递collection.id
,然后通过id查找它,这会使代码复杂化。只需传递集合实例本身
4)CityNamesList
并未提供特定的CityName
,而是从Collection
提供者那里获得的。在这种情况下,将不会重建UI,因为它不会监听CityNamesList
的更改。实际上,它监听Collection
的更改,但是Collection
不知道它的项何时更改,因为没有人在notifyListeners()
上呼叫Collection
/ strong>在CityName@addName
内
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();
}
}