如何在flutter中实现下拉列表?

Cha*_*air 33 dart drop-down-menu flutter

我有一个我希望在Flutter中作为下拉列表实现的位置列表.我对这门语言很陌生.这就是我所做的.

new DropdownButton(
  value: _selectedLocation,
  onChanged: (String newValue) {
    setState(() {
      _selectedLocation = newValue;
     });
},
items: _locations.map((String location) {
  return new DropdownMenuItem<String>(
     child: new Text(location),
  );
}).toList(),
Run Code Online (Sandbox Code Playgroud)

这是我的项目清单:

List<String> _locations = ['A', 'B', 'C', 'D'];
Run Code Online (Sandbox Code Playgroud)

我收到以下错误.

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.
Run Code Online (Sandbox Code Playgroud)

我假设值为_selectedLocationnull.但我正在初始化它.

String _selectedLocation = 'Please choose a location';

小智 38

试试这个

new DropdownButton<String>(
  items: <String>['A', 'B', 'C', 'D'].map((String value) {
    return new DropdownMenuItem<String>(
      value: value,
      child: new Text(value),
    );
  }).toList(),
  onChanged: (_) {},
)
Run Code Online (Sandbox Code Playgroud)


Ali*_*ice 17

使用StatefulWidgetsetState更新下拉列表。

  String _dropDownValue;

  @override
  Widget build(BuildContext context) {
    return DropdownButton(
      hint: _dropDownValue == null
          ? Text('Dropdown')
          : Text(
              _dropDownValue,
              style: TextStyle(color: Colors.blue),
            ),
      isExpanded: true,
      iconSize: 30.0,
      style: TextStyle(color: Colors.blue),
      items: ['One', 'Two', 'Three'].map(
        (val) {
          return DropdownMenuItem<String>(
            value: val,
            child: Text(val),
          );
        },
      ).toList(),
      onChanged: (val) {
        setState(
          () {
            _dropDownValue = val;
          },
        );
      },
    );
  }
Run Code Online (Sandbox Code Playgroud)

下拉的初始状态:

初始状态

打开下拉菜单并选择值:

选择值

将选定的值反映到下拉列表中:

选择的值


Doa*_*Bui 17

如果您不想像Drop list弹出窗口一样显示。您可以像我一样以这种方式自定义它(它会像在同一个平面上一样显示,见下图):

在此处输入图片说明

展开后:

在此处输入图片说明

请按照以下步骤操作: 首先,创建一个名为 的 dart 文件drop_list_model.dart

import 'package:flutter/material.dart';

class DropListModel {
  DropListModel(this.listOptionItems);

  final List<OptionItem> listOptionItems;
}

class OptionItem {
  final String id;
  final String title;

  OptionItem({@required this.id, @required this.title});
}
Run Code Online (Sandbox Code Playgroud)

接下来,创建文件file select_drop_list.dart

import 'package:flutter/material.dart';
import 'package:time_keeping/model/drop_list_model.dart';
import 'package:time_keeping/widgets/src/core_internal.dart';

class SelectDropList extends StatefulWidget {
  final OptionItem itemSelected;
  final DropListModel dropListModel;
  final Function(OptionItem optionItem) onOptionSelected;

  SelectDropList(this.itemSelected, this.dropListModel, this.onOptionSelected);

  @override
  _SelectDropListState createState() => _SelectDropListState(itemSelected, dropListModel);
}

class _SelectDropListState extends State<SelectDropList> with SingleTickerProviderStateMixin {

  OptionItem optionItemSelected;
  final DropListModel dropListModel;

  AnimationController expandController;
  Animation<double> animation;

  bool isShow = false;

  _SelectDropListState(this.optionItemSelected, this.dropListModel);

  @override
  void initState() {
    super.initState();
    expandController = AnimationController(
        vsync: this,
        duration: Duration(milliseconds: 350)
    );
    animation = CurvedAnimation(
      parent: expandController,
      curve: Curves.fastOutSlowIn,
    );
    _runExpandCheck();
  }

  void _runExpandCheck() {
    if(isShow) {
      expandController.forward();
    } else {
      expandController.reverse();
    }
  }

  @override
  void dispose() {
    expandController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: Column(
        children: <Widget>[
          Container(
            padding: const EdgeInsets.symmetric(
                horizontal: 15, vertical: 17),
            decoration: new BoxDecoration(
              borderRadius: BorderRadius.circular(20.0),
              color: Colors.white,
              boxShadow: [
                BoxShadow(
                    blurRadius: 10,
                    color: Colors.black26,
                    offset: Offset(0, 2))
              ],
            ),
            child: new Row(
              mainAxisSize: MainAxisSize.max,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: <Widget>[
                Icon(Icons.card_travel, color: Color(0xFF307DF1),),
                SizedBox(width: 10,),
                Expanded(
                    child: GestureDetector(
                      onTap: () {
                        this.isShow = !this.isShow;
                        _runExpandCheck();
                        setState(() {

                        });
                      },
                      child: Text(optionItemSelected.title, style: TextStyle(
                          color: Color(0xFF307DF1),
                          fontSize: 16),),
                    )
                ),
                Align(
                  alignment: Alignment(1, 0),
                  child: Icon(
                    isShow ? Icons.arrow_drop_down : Icons.arrow_right,
                    color: Color(0xFF307DF1),
                    size: 15,
                  ),
                ),
              ],
            ),
          ),
          SizeTransition(
              axisAlignment: 1.0,
              sizeFactor: animation,
              child: Container(
                margin: const EdgeInsets.only(bottom: 10),
                  padding: const EdgeInsets.only(bottom: 10),
                  decoration: new BoxDecoration(
                    borderRadius: BorderRadius.only(bottomLeft: Radius.circular(20), bottomRight: Radius.circular(20)),
                    color: Colors.white,
                    boxShadow: [
                      BoxShadow(
                          blurRadius: 4,
                          color: Colors.black26,
                          offset: Offset(0, 4))
                    ],
                  ),
                  child: _buildDropListOptions(dropListModel.listOptionItems, context)
              )
          ),
//          Divider(color: Colors.grey.shade300, height: 1,)
        ],
      ),
    );
  }

  Column _buildDropListOptions(List<OptionItem> items, BuildContext context) {
    return Column(
      children: items.map((item) => _buildSubMenu(item, context)).toList(),
    );
  }

  Widget _buildSubMenu(OptionItem item, BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(left: 26.0, top: 5, bottom: 5),
      child: GestureDetector(
        child: Row(
          children: <Widget>[
            Expanded(
              flex: 1,
              child: Container(
                padding: const EdgeInsets.only(top: 20),
                decoration: BoxDecoration(
                  border: Border(top: BorderSide(color: Colors.grey[200], width: 1)),
                ),
                child: Text(item.title,
                    style: TextStyle(
                        color: Color(0xFF307DF1),
                        fontWeight: FontWeight.w400,
                        fontSize: 14),
                    maxLines: 3,
                    textAlign: TextAlign.start,
                    overflow: TextOverflow.ellipsis),
              ),
            ),
          ],
        ),
        onTap: () {
          this.optionItemSelected = item;
          isShow = false;
          expandController.reverse();
          widget.onOptionSelected(item);
        },
      ),
    );
  }

}
Run Code Online (Sandbox Code Playgroud)

初始化值:

DropListModel dropListModel = DropListModel([OptionItem(id: "1", title: "Option 1"), OptionItem(id: "2", title: "Option 2")]);
OptionItem optionItemSelected = OptionItem(id: null, title: "Ch?n quy?n truy c?p");
Run Code Online (Sandbox Code Playgroud)

最后使用它:

SelectDropList(
           this.optionItemSelected, 
           this.dropListModel, 
           (optionItem){
                 optionItemSelected = optionItem;
                    setState(() {
  
                    });
               },
            )
Run Code Online (Sandbox Code Playgroud)


ceg*_*gas 14

对于解决方案,滚动到答案的末尾。

首先,让我们研究一下错误的含义(我引用了Flutter 1.2引发的错误,但是想法是相同的):

断言失败:行560位置15:'item == null || items.isEmpty || 值== null || items.where(((DropdownMenuItem item)=> item.value == value).length == 1':不正确。

有四个or条件。必须至少满足其中之一:

  • 提供了项目(DropdownMenuItem小部件列表)。这样就消除了items == null
  • 提供了非空列表。这样就消除了items.isEmpty
  • _selectedLocation还给出了值()。这样就消除了value == null。请注意,这是DropdownButton的值,而不是DropdownMenuItem的值。

因此,仅保留最后的检查。归结为:

遍历DropdownMenuItem。找到所有value等于的_selectedLocation。然后,检查找到多少与之匹配的项目。必须只有一个具有此值的小部件。否则,抛出错误。

呈现代码的方式,没有DropdownMenuItem值的窗口小部件_selectedLocation。相反,所有小部件的值都设置为null。由于null != _selectedLocation,最后一个条件失败。通过设置_selectedLocationnull- 验证该应用程序应运行。

要解决此问题,我们首先需要为每个设置一个值DropdownMenuItem(以便可以将某些内容传递给onChanged回调):

return DropdownMenuItem(
    child: new Text(location),
    value: location,
);
Run Code Online (Sandbox Code Playgroud)

该应用程序仍将失败。这是因为您的列表仍然不包含_selectedLocation的值。您可以通过两种方式使应用程序工作:

  • 选项1。添加另一个具有值(满足items.where((DropdownMenuItem<T> item) => item.value == value).length == 1)的小部件。如果要让用户重新选择Please choose a location选项,可能会很有用。
  • 选项2。将某些内容传递给hint:paremter并设置selectedLocationnull(满足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(),
          ),
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)


Sed*_*ush 11

对于任何有兴趣实施DropDown自定义的人,class您可以按照以下步骤操作。

  1. 假设您有一个Language使用以下代码调用的类和一个static返回List<Language>

    class Language {
      final int id;
      final String name;
      final String languageCode;
    
      const Language(this.id, this.name, this.languageCode);
    
    
    }
    
     const List<Language> getLanguages = <Language>[
            Language(1, 'English', 'en'),
            Language(2, '?????', 'fa'),
            Language(3, '????', 'ps'),
         ];
    
    Run Code Online (Sandbox Code Playgroud)
  2. 任何你想要实现DropDown,你可以importLanguage类的第一次使用它作为后续

        DropdownButton(
            underline: SizedBox(),
            icon: Icon(
                        Icons.language,
                        color: Colors.white,
                        ),
            items: getLanguages.map((Language lang) {
            return new DropdownMenuItem<String>(
                            value: lang.languageCode,
                            child: new Text(lang.name),
                          );
                        }).toList(),
    
            onChanged: (val) {
                          print(val);
                       },
          )
    
    Run Code Online (Sandbox Code Playgroud)

  • 嗨,亲爱的,这意味着您已经成功实现了“DropdownButton”。但是,不知何故,程序试图在下拉列表中放入重复的值。因此,请确保状态变化。我已经编辑了代码并将列表设置为“const”。请尝试一下,看看是否可以解决您的问题。 (2认同)

Rub*_*ubs 7

您必须考虑到这一点(来自DropdownButton文档):

“项目必须具有不同的值,如果value不为null,则必须在其中。”

所以基本上你有这个字符串列表

List<String> _locations = ['A', 'B', 'C', 'D'];
Run Code Online (Sandbox Code Playgroud)

并且您在Dropdown value属性中的值是这样初始化的:

String _selectedLocation = 'Please choose a location';
Run Code Online (Sandbox Code Playgroud)

只需尝试以下列表:

List<String> _locations = ['Please choose a location', 'A', 'B', 'C', 'D'];
Run Code Online (Sandbox Code Playgroud)

那应该工作:)

如果不想添加这样的String(不在列表上下文中),也请签出“提示”属性,可以使用如下所示的内容:

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(() {});
                  });
Run Code Online (Sandbox Code Playgroud)


小智 7

将值放在 items.then 中,它将起作用,

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(() {});
                })
Run Code Online (Sandbox Code Playgroud)


Dwl*_*hod 6

您需要添加value: location代码才能使用它。检查这个出来。

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


use*_*345 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(),
    ),
  ),
);
...
...
Run Code Online (Sandbox Code Playgroud)

请参考这个颤振网页