【问题标题】:Creating a Dropdown menu inside the bottomsheet in Flutter在 Flutter 的底部表单中创建下拉菜单
【发布时间】:2020-02-04 23:45:11
【问题描述】:

我正在尝试做这样的事情,根据列表内容进行下拉。 我的列表是这样的,

[
    {
        id: val,
        displayName: Enter value,
        type: string, 
        value: "any"
    },
    {
        id: si,
        displayName: Source,
        type: list,
        value: [
            MO
        ],
        data: [
            {id: 1, displayId: MO},
            {id: 2, displayId: AO},
            {id: 3, displayId: OffNet}
        ]
     }
 ]

目前有 2 个条目。将包含这些选项(输入值和来源)的下拉列表显示为下拉列表的 2 个条目

如果选择输入值,则应显示其旁边的文本框,因为它具有字符串类型。 如果选择了下拉列表中的 Source 选项,则另一个包含这些条目(MO、AO、Offnet)的下拉列表应作为下拉值出现,因为它具有一种列表类型。

根据第一个下拉菜单的选择,应选择要显示的小部件(文本框或其他下拉菜单)。

我有一个这样的代码,这将是必要的,但这里将整个页面带到容器中,并且只要选项更改一个调用的setstate,它会重建构建方法,但我想在底片内实现相同的东西,我不知道管理状态,即一旦下拉列表中的选项发生更改,我希望底页能够用数据重建。

代码:

import 'package:flutter/material.dart';

void main() {
  runApp(DropdownExample());
}

class DropdownExample extends StatefulWidget {
  @override
  _DropdownExampleState createState() => _DropdownExampleState();
}

class _DropdownExampleState extends State<DropdownExample> {
  String type;
  int optionId;

  final items = [
    {
      "displayName": "Enter value",
      "type": "string",
    },
    {
      "displayName": "Source",
      "type": "list",
      "data": [
        {"id": 1, "displayId": "MO"},
        {"id": 2, "displayId": "AO"},
        {"id": 3, "displayId": "OffNet"}
      ]
    }
  ];

  @override
  Widget build(BuildContext context) {
    Widget supporting = buildSupportingWidget();

    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text("Dropdown Example")),
        body: Center(
          child: Container(
            height: 600,
            width: 300,
            child: Row(
              children: <Widget>[
                buildMainDropdown(),
                if (supporting != null) supporting,
              ],
            ),
          ),
        ),
      ),
    );
  }

  Expanded buildMainDropdown() {
    return Expanded(
      child: DropdownButtonHideUnderline(
        child: DropdownButton(
          value: type,
          hint: Text("Select a type"),
          items: items
              .map((json) => DropdownMenuItem(
                  child: Text(json["displayName"]), value: json["type"]))
              .toList(),
          onChanged: (newType) {
            setState(() {
              type = newType;
            });
          },
        ),
      ),
    );
  }

  Widget buildSupportingWidget() {
    if (type == "list") {
      List<Map<String, Object>> options = items[1]["data"];
      return Expanded(
        child: DropdownButtonHideUnderline(
          child: DropdownButton(
            value: optionId,
            hint: Text("Select an entry"),
            items: options
                .map((option) => DropdownMenuItem(
                    child: Text(option["displayId"]), value: option["id"]))
                .toList(),
            onChanged: (newId) => setState(() {
              this.optionId = newId;
            }),
          ),
        ),
      );
    } else if (type == "string") {
      return Expanded(child: TextFormField());
    }
    return null;
  }
}

上面的代码工作正常,但我想做的是同样的事情应该出现在底部表中,并具有确切的功能。

每当按下“打开底页”按钮时,都会弹出一个底页并将代码结果显示为底页的内容。

我做过类似的事情,但它不起作用

import 'package:flutter/material.dart';

void main() {
  runApp(DropdownExample());
}

class DropdownExample extends StatefulWidget {
  @override
  _DropdownExampleState createState() => _DropdownExampleState();
}

class _DropdownExampleState extends State<DropdownExample> {
  String type;
  int optionId;

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text("Dropdown Example")),
        body: Center(
          child: Container(
            height: 600,
            width: 300,
            child: Row(
              children: <Widget>[
                Align(
                    alignment: Alignment.topRight,
                    child: FlatButton.icon(
                      label: Text('Filters'),
                      icon: Icon(Icons.filter_list),
                       onPressed: showModalSheet(),
                       )),
              ],
            ),
          ),
        ),
      ),
    );
  }

showModalSheet() {

final items = [
    {
      "displayName": "Enter value",
      "type": "string",
    },
    {
      "displayName": "Source",
      "type": "list",
      "data": [
        {"id": 1, "displayId": "MO"},
        {"id": 2, "displayId": "AO"},
        {"id": 3, "displayId": "OffNet"}
      ]
    }
  ];

     showModalBottomSheet<void>(
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(10.0),
        ),
        context: context,
        builder: (BuildContext context) {
          return StatefulBuilder(
              builder: (BuildContext context, StateSetter state) {
            return createBox(context, items, state);
          });
        });

}

createBox(BuildContext context, List<Map<String,Object>> val,StateSetter state) {
      Widget supporting = buildSupportingWidget(val);
    return SingleChildScrollView(
      child: LimitedBox(
        child: Column(
          mainAxisSize: MainAxisSize.max,
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
               buildMainDropdown(val),
                if (supporting != null) supporting
          ]
        )
      )
    );

}



  Expanded buildMainDropdown(List<Map<String,Object>> items) {
    return Expanded(
      child: DropdownButtonHideUnderline(
        child: DropdownButton(
          value: type,
          hint: Text("Select a type"),
          items: items
              .map((json) => DropdownMenuItem(
                  child: Text(json["displayName"]), value: json["type"]))
              .toList(),
          onChanged: (newType) {
            setState(() {
              type = newType;
            });
          },
        ),
      ),
    );
  }

  Widget buildSupportingWidget(List<Map<String,Object>>items) {
    if (type == "list") {
      List<Map<String, Object>> options = items[1]["data"];
      return Expanded(
        child: DropdownButtonHideUnderline(
          child: DropdownButton(
            value: optionId,
            hint: Text("Select an entry"),
            items: options
                .map((option) => DropdownMenuItem(
                    child: Text(option["displayId"]), value: option["id"]))
                .toList(),
            onChanged: (newId) => setState(() {
              this.optionId = newId;
            }),
          ),
        ),
      );
    } else if (type == "string") {
      return Expanded(child: TextFormField());
    }
    return null;
  }
}

让我知道需要的更改,谢谢

【问题讨论】:

    标签: flutter dart drop-down-menu bottom-sheet


    【解决方案1】:

    第 1 步:LimitedBox 需要 maxHeight
    第2步:函数showModalSheet需要传递上下文
    第 3 步: createBox 、 buildMainDropdown 和 buildSupportingWidget 需要为 StatefulBuilder 传递状态

    完整代码

    import 'package:flutter/material.dart';
    
    void main() => runApp(MyApp());
    
    class MyApp extends StatelessWidget {
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          theme: ThemeData(
            // This is the theme of your application.
            //
            // Try running your application with "flutter run". You'll see the
            // application has a blue toolbar. Then, without quitting the app, try
            // changing the primarySwatch below to Colors.green and then invoke
            // "hot reload" (press "r" in the console where you ran "flutter run",
            // or simply save your changes to "hot reload" in a Flutter IDE).
            // Notice that the counter didn't reset back to zero; the application
            // is not restarted.
            primarySwatch: Colors.blue,
          ),
          home: DropdownExample(),
        );
      }
    }
    
    class DropdownExample extends StatefulWidget {
      @override
      _DropdownExampleState createState() => _DropdownExampleState();
    }
    
    class _DropdownExampleState extends State<DropdownExample> {
      String type;
      int optionId;
    
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          home: Scaffold(
            appBar: AppBar(title: Text("Dropdown Example")),
            body: Center(
              child: Container(
                height: 600,
                width: 300,
                child: Row(
                  children: <Widget>[
                    Align(
                        alignment: Alignment.topRight,
                        child: FlatButton.icon(
                          label: Text('Filters'),
                          icon: Icon(Icons.filter_list),
                          // onPressed: showModalSheet(),
                          onPressed: () {
                            showModalSheet(context);
                          },
                        )),
                  ],
                ),
              ),
            ),
          ),
        );
      }
    
      void showModalSheet(BuildContext context) {
        final items = [
          {
            "displayName": "Enter value",
            "type": "string",
          },
          {
            "displayName": "Source",
            "type": "list",
            "data": [
              {"id": 1, "displayId": "MO"},
              {"id": 2, "displayId": "AO"},
              {"id": 3, "displayId": "OffNet"}
            ]
          }
        ];
    
        showModalBottomSheet<void>(
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(10.0),
            ),
            context: context,
            builder: (BuildContext context) {
              return StatefulBuilder(
                  builder: (BuildContext context, StateSetter state) {
                    return createBox(context, items, state);
                  });
            });
      }
    
    
    
      createBox(BuildContext context, List<Map<String,Object>> val,StateSetter state) {
        Widget supporting = buildSupportingWidget(val,state);
        return SingleChildScrollView(
            child: LimitedBox(
                maxHeight: 300,
                child: Column(
                    mainAxisSize: MainAxisSize.max,
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      buildMainDropdown(val,state),
                      if (supporting != null) supporting
                    ]
                )
            )
        );
    
      }
    
    
    
      Expanded buildMainDropdown(List<Map<String,Object>> items,StateSetter setState) {
        return Expanded(
          child: DropdownButtonHideUnderline(
            child: DropdownButton(
              value: type,
              hint: Text("Select a type"),
              items: items
                  .map((json) => DropdownMenuItem(
                  child: Text(json["displayName"]), value: json["type"]))
                  .toList(),
              onChanged: (newType) {
                setState(() {
                  type = newType;
                });
              },
            ),
          ),
        );
      }
    
      Widget buildSupportingWidget(List<Map<String,Object>>items, StateSetter setState) {
        if (type == "list") {
          List<Map<String, Object>> options = items[1]["data"];
          return Expanded(
            child: DropdownButtonHideUnderline(
              child: DropdownButton(
                value: optionId,
                hint: Text("Select an entry"),
                items: options
                    .map((option) => DropdownMenuItem(
                    child: Text(option["displayId"]), value: option["id"]))
                    .toList(),
                onChanged: (newId) => setState(() {
                  this.optionId = newId;
                }),
              ),
            ),
          );
        } else if (type == "string") {
          return Expanded(child: TextFormField());
        }
        return null;
      }
    }
    

    【讨论】:

    • 感谢您的帮助。但是在我的代码中,我已经声明了一个包含字符串和列表的最终列表,如果我在列表中再添加一个,我会得到异常,对于列表,我正在执行硬编码,即在 buildSupportingWidget 中,如果它的列表我是通过此 List> options = items[1]["data"]; 获取选项的值这是错误的,所以我遇到了异常,如果列表是动态的,有什么方法可以期待正确的行为,意味着可能包含任何字符串和列表。谢谢
    • 最终列表无法添加项目。请使用var声明
    • 动态意味着没有编译时检查。
    猜你喜欢
    • 1970-01-01
    • 2015-10-08
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多