我正在使用带有Flutter和提供程序模式的应用程序。我有一个特别的ViewModel,它随Provider.of<AddressBookModel>(context)
提供。
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<AddressBookViewModel>(
builder:(_) => AddressBookViewModel(),
child: Scaffold(
body: _getBody(context);
}
Widget _getBody(BuildContext context) {
AddressBookViewModel vm = Provider.of<AddressBookViewModel>(context);
// AddressBookViewModel holds a list of contact objects
// (id, name, street, starred etc.)
List<Contact> contacts = vm.contacts;
return ListView.builder(
itemCount: contacts.length,
itemBuilder: (context, index) => ListTile(
title: Text(contacts[index].name),
trailing: contacts[index].starred
? Icon(Icons.star))
: null,
/**
* Changing one object rebuilds and redraws the whole list
*/
onLongPress: () => vm.toggleStarred(contacts[index]);
));
}
}
以及相应的ViewModel
class AddressBookViewModel with ChangeNotifier {
final List<Contact> contacts;
AddressBookViewModel({this.contacts = []});
void toggleStarred(Contact contact) {
int index = contacts.indexOf(contact);
// the contact object is immutable
contacts[index] = contact.copy(starred: !contact.starred);
notifyListeners();
}
}
我面临的问题是,一旦我使用toggleStarred()
更改列表中的一个联系人对象,
提供者正在重建并重新绘制整个列表。我认为这是没有必要的,因为
一项需要重建。有什么办法让提供者只负责
一个清单项目?或其他解决此问题的方法?
答案 0 :(得分:1)
使用列表时,您需要为列表中的每个项目都有一个“提供者”,并将列表项提取到常量中-特别是在与项目相关联的数据是不可变的情况下。
代替:
final contactController = Provider.of<ContactController>(context);
return ListView.builder(
itemCount: contactController.contacts.length,
builder: (_, index) {
reurn Text(contactController.contacts[index].name);
}
)
首选:
final contactController = Provider.of<ContactController>(context);
return ListView.builder(
itemCount: contactController.contacts.length,
builder: (_, index) {
reurn Provider.value(
value: contactController.contacts[index],
child: const ContactItem(),
);
}
)
ContactItem
是StatelessWidget
的地方,通常看起来像这样:
class ContactItem extends StatelessWidget {
const ContactItem({Key key}): super(key: key);
@override
Widget build(BuildContext context) {
return Text(Provider.of<Contact>(context).name);
}
}
答案 1 :(得分:0)
class Contact with ChangeNotifier { }
bool starred;
void toggleStarred() {
starred = !starred;
notifyListeners();
}
class Contact with ChangeNotifier {
final String name;
bool starred;
Contact(this.name, this.starred);
void toggleStarred() {
starred = !starred;
notifyListeners();
}
}
class ContactView extends StatelessWidget {
Widget build(BuildContext context) {
return ListTile();
}
}
(context, index) {
return ChangeNotifierProvider.value(
value: contacts[index],
child: ContactView(),
);
final contact = Provider.of<Contact>(context);
onLongPress: () => contact.toggleStarred(),
class ContactView extends StatelessWidget {
@override
Widget build(BuildContext context) {
final contact = Provider.of<Contact>(context);
print("building ListTile item with contact " + contact.name);
return ListTile(
title: Text(contact.name),
trailing: contact.starred ? Icon(Icons.star) : null,
onLongPress: () => contact.toggleStarred(),
);
}
}
步骤[5]代码更改审核:
return ListView.builder(
itemCount: contacts.length,
itemBuilder: (context, index) {
print("building ListView item with index $index");
return ChangeNotifierProvider.value(
value: contacts[index],
child: ContactView(),
);
},
);
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
void main() {
runApp(
ChangeNotifierProvider<AddressBookViewModel>(
builder: (context) => AddressBookViewModel(),
child: HomeScreen(),
),
);
}
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<AddressBookViewModel>(
builder: (context) => AddressBookViewModel(),
child: MaterialApp(
home: Scaffold(
body: _getBody(context),
),
),
);
}
Widget _getBody(BuildContext context) {
AddressBookViewModel vm = Provider.of<AddressBookViewModel>(context);
final contacts = vm.contacts;
return ListView.builder(
itemCount: contacts.length,
itemBuilder: (context, index) {
print("building ListView item with index $index");
return ChangeNotifierProvider.value(
value: contacts[index],
child: ContactView(),
);
},
);
}
}
// product_item.dart
class ContactView extends StatelessWidget {
@override
Widget build(BuildContext context) {
final contact = Provider.of<Contact>(context);
print("building ListTile item with contact " + contact.name);
return ListTile(
title: Text(contact.name),
trailing: contact.starred ? Icon(Icons.star) : null,
onLongPress: () => contact.toggleStarred(),
);
}
}
class AddressBookViewModel with ChangeNotifier {
final contacts = [
Contact("Contact A", false),
Contact("Contact B", false),
Contact("Contact C", false),
Contact("Contact D", false),
];
void addcontacts(Contact contact) {
contacts.add(contact);
notifyListeners();
}
}
class Contact with ChangeNotifier {
final String name;
bool starred;
Contact(this.name, this.starred);
void toggleStarred() {
starred = !starred;
notifyListeners();
}
}