Ответ 1
Попробуй это
new DropdownButton<String>(
items: <String>['A', 'B', 'C', 'D'].map((String value) {
return new DropdownMenuItem<String>(
value: value,
child: new Text(value),
);
}).toList(),
onChanged: (_) {},
)
У меня есть список мест, которые я хочу реализовать в качестве раскрывающегося списка в Flutter. Im довольно новичок в языке. Вот что я сделал.
new DropdownButton(
value: _selectedLocation,
onChanged: (String newValue) {
setState(() {
_selectedLocation = newValue;
});
},
items: _locations.map((String location) {
return new DropdownMenuItem<String>(
child: new Text(location),
);
}).toList(),
Это мой список предметов:
List<String> _locations = ['A', 'B', 'C', 'D'];
И я получаю следующую ошибку.
Another exception was thrown: 'package:flutter/src/material/dropdown.dart': Failed assertion: line 468 pos 15: 'value == null || items.where((DropdownMenuItem<T> item) => item.value == value).length == 1': is not true.
Я предполагаю, что значение _selectedLocation
получает значение null. Но я инициализирую его так.
String _selectedLocation = 'Please choose a location';
Попробуй это
new DropdownButton<String>(
items: <String>['A', 'B', 'C', 'D'].map((String value) {
return new DropdownMenuItem<String>(
value: value,
child: new Text(value),
);
}).toList(),
onChanged: (_) {},
)
Для решения прокрутите до конца ответа.
Прежде всего, давайте разберемся, что говорит ошибка (я привел ошибку, выданную Flutter 1.2, но идея та же):
Failed assertion: line 560 pos 15: 'items == null || items.isEmpty || value == null || items.where((DropdownMenuItem item) => item.value == value).length == 1': is not true.
Существует четыре условия or
. Необходимо выполнить хотя бы одно из них:
DropdownMenuItem
) были предоставлены. Это исключает items == null
.items.isEmpty
._selectedLocation
). Это устраняет value == null
. Обратите внимание, что это значение DropdownButton
, а не DropdownMenuItem
.Следовательно, остается только последняя проверка. Это сводится к чему-то вроде:
Итерируйте по
DropdownMenuItem
. Найдите все, у которых естьvalue
, равный_selectedLocation
. Затем проверьте, сколько предметов было найдено. Должен быть ровно один виджет с таким значением. В противном случае выведите ошибку.
Представлен код пути, отсутствует виджет DropdownMenuItem
со значением _selectedLocation
. Вместо этого все виджеты имеют значение null
. Начиная с null != _selectedLocation
, последнее условие не выполняется. Проверьте это, установив _selectedLocation
в null
- приложение должно запуститься.
Чтобы решить эту проблему, нам сначала нужно установить значение для каждого DropdownMenuItem
(чтобы что-то могло быть передано в обратный вызов onChanged
):
return DropdownMenuItem(
child: new Text(location),
value: location,
);
Приложение по-прежнему не работает. Это потому, что ваш список по-прежнему не содержит значение _selectedLocation
. Вы можете заставить приложение работать двумя способами:
items.where((DropdownMenuItem<T> item) => item.value == value).length == 1
). Может быть полезно, если вы хотите позволить пользователю повторно выбрать опцию Please choose a location
.hint:
и установите selectedLocation
в null
(чтобы удовлетворить условию value == null
). Полезно, если вы не хотите, чтобы Please choose a location
оставался опцией.Посмотрите код ниже, который показывает, как это сделать:
import 'package:flutter/material.dart';
void main() {
runApp(Example());
}
class Example extends StatefulWidget {
@override
State<StatefulWidget> createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
// List<String> _locations = ['Please choose a location', 'A', 'B', 'C', 'D']; // Option 1
// String _selectedLocation = 'Please choose a location'; // Option 1
List<String> _locations = ['A', 'B', 'C', 'D']; // Option 2
String _selectedLocation; // Option 2
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Center(
child: DropdownButton(
hint: Text('Please choose a location'), // Not necessary for Option 1
value: _selectedLocation,
onChanged: (newValue) {
setState(() {
_selectedLocation = newValue;
});
},
items: _locations.map((location) {
return DropdownMenuItem(
child: new Text(location),
value: location,
);
}).toList(),
),
),
),
);
}
}
вы должны учитывать это (из документов DropdownButton):
"Элементы должны иметь разные значения, а если значение не равно нулю, оно должно быть среди них".
Итак, в основном у вас есть этот список строк
List<String> _locations = ['A', 'B', 'C', 'D'];
И ваше значение в свойстве Dropdown value инициализируется следующим образом:
String _selectedLocation = 'Please choose a location';
Просто попробуйте этот список:
List<String> _locations = ['Please choose a location', 'A', 'B', 'C', 'D'];
Это должно работать :)
Также проверьте свойство "hint", если вы не хотите добавлять такую строку (из контекста списка), вы можете пойти примерно так:
DropdownButton<int>(
items: locations.map((String val) {
return new DropdownMenuItem<String>(
value: val,
child: new Text(val),
);
}).toList(),
hint: Text("Please choose a location"),
onChanged: (newVal) {
_selectedLocation = newVal;
this.setState(() {});
});
Вам нужно добавить value: location
в вашем коде, чтобы работать. Проверьте это.
items: _locations.map((String location) {
return new DropdownMenuItem<String>(
child: new Text(location),
value: location,
);
}).toList(),
поместите значение внутри предметов. Затем оно будет работать,
new DropdownButton<String>(
items:_dropitems.map((String val){
return DropdownMenuItem<String>(
value: val,
child: new Text(val),
);
}).toList(),
hint:Text(_SelectdType),
onChanged:(String val){
_SelectdType= val;
setState(() {});
})
Вы можете использовать класс DropDownButton
для создания выпадающего списка:
...
...
String dropdownValue = 'One';
...
...
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: DropdownButton<String>(
value: dropdownValue,
onChanged: (String newValue) {
setState(() {
dropdownValue = newValue;
});
},
items: <String>['One', 'Two', 'Free', 'Four']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
),
),
);
...
...
пожалуйста, обратитесь к этой странице флаттера
Я столкнулся с аналогичной проблемой с DropDownButton, когда я пытался отобразить динамический список строк в раскрывающемся списке. Я закончил создание плагина: flutter_search_panel. Не выпадающий плагин, но вы можете отображать элементы с функцией поиска.
Используйте следующий код для использования виджета:
FlutterSearchPanel(
padding: EdgeInsets.all(10.0),
selected: 'a',
title: 'Demo Search Page',
data: ['This', 'is', 'a', 'test', 'array'],
icon: new Icon(Icons.label, color: Colors.black),
color: Colors.white,
textStyle: new TextStyle(color: Colors.black, fontWeight: FontWeight.bold, fontSize: 20.0, decorationStyle: TextDecorationStyle.dotted),
onChanged: (value) {
print(value);
},
),
Допустим, мы создаем выпадающий список валют:
List _currency = ["INR", "USD", "SGD", "EUR", "PND"];
List<DropdownMenuItem<String>> _dropDownMenuCurrencyItems;
String _currentCurrency;
List<DropdownMenuItem<String>> getDropDownMenuCurrencyItems() {
List<DropdownMenuItem<String>> items = new List();
for (String currency in _currency) {
items.add(
new DropdownMenuItem(value: currency, child: new Text(currency)));
}
return items;
}
void changedDropDownItem(String selectedCurrency) {
setState(() {
_currentCurrency = selectedCurrency;
});
}
Добавьте ниже код в части тела:
new Row(children: <Widget>[
new Text("Currency: "),
new Container(
padding: new EdgeInsets.all(16.0),
),
new DropdownButton(
value: _currentCurrency,
items: _dropDownMenuCurrencyItems,
onChanged: changedDropDownItem,
)
])
Вы получаете ошибку из-за запроса свойства нулевого объекта. Ваш элемент должен быть нулевым, поэтому при запросе его значения для сравнения вы получаете эту ошибку. Убедитесь, что вы получаете данные или ваш список представляет собой список объектов, а не простых строк.
Когда я столкнулся с вопросом о том, что мне нужен менее общий DropdownStringButton, я просто создал его:
dropdown_string_button.dart
import 'package:flutter/material.dart';
// Subclass of DropdownButton based on String only values.
// Yes, I know Flutter discourages subclassing, but this seems to be
// a reasonable exception where a commonly used specialization can be
// made more easily usable.
//
// Usage:
// DropdownStringButton(items: ['A', 'B', 'C'], value: 'A', onChanged: (string) {})
//
class DropdownStringButton extends DropdownButton<String> {
DropdownStringButton({
Key key, @required List<String> items, value, hint, disabledHint,
@required onChanged, elevation = 8, style, iconSize = 24.0, isDense = false,
isExpanded = false, }) :
assert(items == null || value == null || items.where((String item) => item == value).length == 1),
super(
key: key,
items: items.map((String item) {
return DropdownMenuItem<String>(child: Text(item), value: item);
}).toList(),
value: value, hint: hint, disabledHint: disabledHint, onChanged: onChanged,
elevation: elevation, style: style, iconSize: iconSize, isDense: isDense,
isExpanded: isExpanded,
);
}
Это случилось со мной, когда я заменил значение по умолчанию на новое динамическое значение. Но каким-то образом ваш код может зависеть от этого значения по умолчанию. Так что попробуйте сохранить константу со значением по умолчанию, хранящимся где-то в резерве.
const defVal = 'abcd';
String dynVal = defVal;
// dropdown list whose value is dynVal that keeps changing with onchanged
// when rebuilding or setState((){})
dynVal = defVal;
// rebuilding here...
+ Изменить
List<String> _locations = ['A', 'B', 'C', 'D'];
к
List<String> _locations = [_selectedLocation, 'A', 'B', 'C', 'D'];
_selectedLocation должно быть частью вашего списка товаров;
Как я могу добавить значения, полученные с помощью текстового поля, в раскрывающийся список, используя технологию флаттера, редактор кода VS.