[英]I'm trying to get the contacts from the emulator to a dropdownlist and let the user to select one. I'm getting an error
Probably the contacts have duplicates, but I want the duplicates to be accepted.可能联系人有重复项,但我希望接受重复项。 The basic idea is to access the contact list and populate the values to a dropdownMenu and let the user to select a contact from there and save to a file.
基本思想是访问联系人列表并将值填充到下拉菜单中,让用户从那里到 select 联系人并保存到文件中。 I have already initialised the dropdownMenu with a string "Select a contact" through a variable.
我已经通过变量用字符串“选择联系人”初始化了下拉菜单。
Exception has occurred.
_AssertionError ('package:flutter/src/material/dropdown.dart': Failed assertion: line 890 pos 15: 'items == null || items.isEmpty || value == null ||
items.where((DropdownMenuItem<T> item) {
return item.value == value;
}).length == 1': There should be exactly one item with [DropdownButton]'s value: Select a contact.
Either zero or 2 or more [DropdownMenuItem]s were detected with the same value)
Here is the complete code这是完整的代码
import 'package:flutter/material.dart';
import 'package:contacts_service/contacts_service.dart';
import 'package:permission_handler/permission_handler.dart';
import 'dart:io';
import 'dart:convert';
import 'package:url_launcher/url_launcher.dart';
import 'package:path_provider/path_provider.dart';
class Interface extends StatelessWidget {
const Interface({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('pAM'),
),
body: const ContactSelector(),
);
}
}
class ContactSelector extends StatefulWidget {
const ContactSelector({super.key});
@override
_ContactSelectorState createState() => _ContactSelectorState();
}
class _ContactSelectorState extends State<ContactSelector> {
Contact _selectedContact = Contact();
late bool _isTrue;
late Iterable<Contact> _contacts;
List<DropdownMenuItem<String>> _dropdownItems = [];
String _selectedName = "Select Contact";
//late List<DropdownMenuItem<String>> _dropdownItems;
@override
void initState() {
super.initState();
_getContacts();
_selectedName = _dropdownItems.isNotEmpty
? _dropdownItems[0].value!
: 'Select a contact';
}
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
if (_dropdownItems != null)
DropdownButton<String>(
value: _selectedName,
items: _dropdownItems,
onChanged: (newValue) {
_onContactChanged(newValue!);
},
)
else
const Text("Loading...")
],
);
}
String? encodeQueryParameters(Map<String, String> params) {
return params.entries
.map((e) =>
'${Uri.encodeComponent(e.key)}=${Uri.encodeComponent(e.value)}')
.join('&');
}
void _sendMessage(String message) async {
String phoneNumber = _selectedContact.phones.toString();
Uri uri = Uri(
scheme: 'sms',
path: phoneNumber,
query: encodeQueryParameters(<String, String>{
'body': 'Welcome to pAM',
}),
);
if (await canLaunchUrl(uri)) {
await canLaunchUrl(uri);
} else {
throw 'Could not send SMS';
}
}
_getContacts() async {
_contacts = await ContactsService.getContacts(withThumbnails: false);
_dropdownItems = _contacts
.map((c) => DropdownMenuItem(
value: c.displayName,
child: Text(c.displayName.toString()),
))
.toList();
setState(() {});
}
_onContactChanged(String newValue) {
setState(() {
_selectedName = newValue;
_selectedContact =
_contacts.firstWhere((c) => c.displayName == _selectedName);
});
_saveContactToFile(_selectedContact);
_readJson();
}
_saveContactToFile(Contact contact) async {
final directory = await getApplicationDocumentsDirectory();
final file = File('${directory.path}/selected_contact.txt');
if (!(await file.exists())) {
file.create();
}
file.writeAsString(jsonEncode(contact.toMap()));
}
void _readJson() async {
final directory = await getApplicationDocumentsDirectory();
final file = File('${directory.path}/true.json');
if (await file.exists()) {
final content = jsonDecode(await file.readAsString());
if (content["isTrue"]) {
_promptMessage();
} else {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Reminder'),
content: const Text(
"You can continue your work, remember your loved ones misses you"),
actions: <Widget>[
ElevatedButton(
child: const Text('OK'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
});
}
}
}
_promptMessage() {
if (_isTrue) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: const Text('Select a message'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
InkWell(
child: const Text('How are you?'),
onTap: () {
_sendMessage('How are you?');
}),
InkWell(
child: const Text('What are you up to?'),
onTap: () {
_sendMessage('What are you up to?');
}),
InkWell(
child: const Text('What is for dinner?'),
onTap: () {
_sendMessage('What is for dinner?');
}),
],
),
),
actions: <Widget>[
ElevatedButton(
child: const Text('Cancel'),
onPressed: () {
Navigator.of(context).pop();
},
),
],
);
},
);
}
}
}
This is the key part of the error message: There should be exactly one item with [DropdownButton]'s value: Select a contact.
这是错误消息的关键部分:
There should be exactly one item with [DropdownButton]'s value: Select a contact.
You are setting the value
of the DropdownButton
to "Select a contact"
(presumably because _dropdownItems.isNotEmpty == false
), but none of the DropdownMenuItem
s that you have given to the DropdownButton
via its items
property has "Select a contact"
as its value.您正在将
DropdownButton
的value
设置为"Select a contact"
(大概是因为_dropdownItems.isNotEmpty == false
),但是您通过其items
属性提供给DropdownButton
的DropdownMenuItem
都没有"Select a contact"
作为其价值。 You might want to look into the use of the hint
property to show the "Select a contact"
, well, hint.您可能想查看
hint
属性的使用,以显示"Select a contact"
,好吧,提示。
Something like the (untested) code below:类似于下面的(未经测试的)代码:
DropdownButton<String>(
hint: Text("Select a contact")
value: _dropdownItems.isNotEmpty ? _dropdownItems.first : null,
items: _dropdownItems,
onChanged: (newValue) {
_onContactChanged(newValue!);
},
)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.