我有一个要使用contacts_service插件加载到ListView中的联系人列表。对于每个联系人,我想先检查是否已将它们标记为isFavourite
,这取决于检查他们的ID是否在SharedPreferences
的列表中。如果是这样,那么我们会在名称旁边显示一个星星。
因为检查SharedPreferences需要一个Future,我该如何做到这一点?到目前为止,进展如下。
联系人屏幕:
@override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: contacts?.length,
itemBuilder: (BuildContext context, int index) {
Contact c = contacts?.elementAt(index);
return ListTile(
// Show star next to Contact's name
leading: c.isFavourite ? Icon(Icons.star) : null,
title: Text(c.name);
);
}
);
);
}
共享首选项:
static Future<bool> checkIsFavourite(String contactId) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
List<String> favouriteContacts = prefs.getStringList("Favourites");
return favouriteContacts.contains(contactId);
}
联系人服务:
class ContactsService {
static const MethodChannel _channel =
MethodChannel('github.com/clovisnicolas/flutter_contacts');
/// Fetches all contacts, or when specified, the contacts with a name
/// matching [query]
static Future<Iterable<Contact>> getContacts(
{String query, bool withThumbnails = true}) async {
Iterable contacts = await _channel.invokeMethod('getContacts',
<String, dynamic>{'query': query, 'withThumbnails': withThumbnails});
return contacts.map((m) => Contact.fromMap(m));
}
联系方式:
class Contact {
Contact(
{this.givenName,
this.middleName,
this.prefix,
this.suffix,
this.familyName,
this.company,
this.jobTitle,
this.emails,
this.phones,
this.postalAddresses,
this.avatar,
this.note,
this.isSelected});
String identifier,
displayName,
givenName,
middleName,
prefix,
suffix,
familyName,
company,
jobTitle,
note;
Iterable<Item> emails = [];
Iterable<Item> phones = [];
Iterable<PostalAddress> postalAddresses = [];
Uint8List avatar;
bool isSelected;
String initials() {
return ((this.givenName?.isNotEmpty == true ? this.givenName[0] : "") +
(this.familyName?.isNotEmpty == true ? this.familyName[0] : ""))
.toUpperCase();
}
Contact.fromMap(Map m) {
identifier = m["identifier"];
displayName = m["displayName"];
givenName = m["givenName"];
middleName = m["middleName"];
familyName = m["familyName"];
prefix = m["prefix"];
suffix = m["suffix"];
company = m["company"];
jobTitle = m["jobTitle"];
emails = (m["emails"] as Iterable)?.map((m) => Item.fromMap(m));
phones = (m["phones"] as Iterable)?.map((m) => Item.fromMap(m));
postalAddresses = (m["postalAddresses"] as Iterable)
?.map((m) => PostalAddress.fromMap(m));
avatar = m["avatar"];
note = m["note"];
isSelected = SharedPreferences.checkIsFavourite(m["identifier"]);
// What is the correct way to check if it's a favourite?
}
答案 0 :(得分:1)
我建议定义一个应用程序级的超级变量,该变量在应用程序启动时初始化。
例如 main.dart
SharedPreferences prefs;
void main() async {
prefs = await SharedPreferences.getInstance();
return runApp(MyApp());
}
然后,您可以将prefs
变量以构造函数参数的形式传递到需要它的任何其他屏幕/小部件。例如
class ContactsScreen extends StatefulWidget {
ContactsScreen({
Key key,
@required this.prefs,
}):
super(key: key);
final SharedPreferences prefs;
...
}
您可能已经在代码中注意到,每次在SharedPreferences
中建立联系人时都会调用ListView
初始化,然后再进行prefs.getStringList("Favourites")
调用。
这2个操作比较繁琐,如果您一次定义收藏夹数组并将其用于每个联系人构建调用,则可以避免。
我将如何在接受isFavourite
作为参数的Contact
对象中创建List<String>
函数。例如
class Contact {
...
bool isFavourite(List<String> favouriteIds) {
assert(favouriteIds != null);
return favouriteIds.contains(this.identifier);
}
...
}
以及在联系人屏幕build
中:
final List<String> favouriteIds = prefs.getStringList("Favourites") ?? []; // Use empty array in case `Favourites` is not set
...
ListTile(
// Show star next to Contact's name
leading: contact.isFavourite(favouriteIds) ? Icon(Icons.star) : null,
title: Text(contact.name);
);
...
但是,我必须警告您,我不知道Dart / Flutter中如何处理全局(/ super / app范围)变量,以及声明 (更新) main()
方法是否是一个好主意为async
,请您自担风险。
根据我的亲身经历-到目前为止,我还没有遇到任何问题。
已更新
如果perfectly safe则将main()
声明为async
。
关于全局变量-尽管有一个even better one,我的方法还是可以的。