Как реализовать выпадающий список во флаттер?

У меня есть список мест, которые я хочу реализовать в качестве раскрывающегося списка в 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';

Ответ 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: (_) {},
)

Ответ 2

Для решения прокрутите до конца ответа.

Прежде всего, давайте разберемся, что говорит ошибка (я привел ошибку, выданную 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. Вы можете заставить приложение работать двумя способами:

  • Вариант 1. Добавьте другой виджет, который имеет значение (для удовлетворения items.where((DropdownMenuItem<T> item) => item.value == value).length == 1). Может быть полезно, если вы хотите позволить пользователю повторно выбрать опцию Please choose a location.
  • Вариант 2. Передайте что-нибудь паремтеру 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(),
          ),
        ),
      ),
    );
  }
}

Ответ 3

вы должны учитывать это (из документов 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(() {});
                  });

Ответ 4

Вам нужно добавить value: location в вашем коде, чтобы работать. Проверьте это.

items: _locations.map((String location) {
  return new DropdownMenuItem<String>(
     child: new Text(location),
     value: location,
  );
}).toList(),

Ответ 5

поместите значение внутри предметов. Затем оно будет работать,

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(() {});
                })

Ответ 6

Вы можете использовать класс 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(),
    ),
  ),
);
...
...

пожалуйста, обратитесь к этой странице флаттера

Ответ 7

Я столкнулся с аналогичной проблемой с 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);
        },
   ),

Ответ 8

Допустим, мы создаем выпадающий список валют:

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,
  )
])

Ответ 9

Вы получаете ошибку из-за запроса свойства нулевого объекта. Ваш элемент должен быть нулевым, поэтому при запросе его значения для сравнения вы получаете эту ошибку. Убедитесь, что вы получаете данные или ваш список представляет собой список объектов, а не простых строк.

Ответ 10

Когда я столкнулся с вопросом о том, что мне нужен менее общий 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,
        );
    }

Ответ 11

Это случилось со мной, когда я заменил значение по умолчанию на новое динамическое значение. Но каким-то образом ваш код может зависеть от этого значения по умолчанию. Так что попробуйте сохранить константу со значением по умолчанию, хранящимся где-то в резерве.

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...

Ответ 12

+ Изменить

List<String> _locations = ['A', 'B', 'C', 'D'];

к

List<String> _locations = [_selectedLocation, 'A', 'B', 'C', 'D'];

_selectedLocation должно быть частью вашего списка товаров;

Ответ 13

Как я могу добавить значения, полученные с помощью текстового поля, в раскрывающийся список, используя технологию флаттера, редактор кода VS.