【问题标题】:Dropdown button not showing selected value in Flutter下拉按钮未在 Flutter 中显示所选值
【发布时间】:2020-01-03 10:02:06
【问题描述】:

我是 Flutter 开发的新手,我正在尝试显示下拉列表的选定值,但我无法让它工作。

下拉菜单不会将其显示为已选择的,它只是继续,好像没有选择任何内容。请帮我解决问题。

这是我的代码

    import 'dart:convert';
    import 'package:sqlliteapp/db_helper.dart';
    import 'package:sqlliteapp/user_model.dart';
    import 'package:http/http.dart' as http;

    import 'package:flutter/material.dart';

    class SqliteDropdown extends StatefulWidget {
      @override
      SqliteDropdownState createState() {
        return new SqliteDropdownState();
      }
    }

    class SqliteDropdownState extends State<SqliteDropdown> {
      DatabaseHelper db = DatabaseHelper();

      //Add data to db
      _saveData() async {
        UserModel user1 = UserModel(
          "test",
          "test",
          "test@gmail.com",
          "test",
        );

        UserModel user2 = UserModel(
          "test1",
          "test1",
          "test1@gmail.com",
          "test",
        );
        await db.saveData(user1);
        await db.saveData(user2);
      }

      @override
      void initState() {
        super.initState();
        _saveData();
      }

      UserModel _currentUser;

      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('Fetching data from Sqlite DB - DropdownButton'),
          ),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              mainAxisSize: MainAxisSize.max,
              children: <Widget>[
                FutureBuilder<List<UserModel>>(
                    future: db.getUserModelData(),
                    builder: (BuildContext context,
                        AsyncSnapshot<List<UserModel>> snapshot) {
                      if (!snapshot.hasData) return CircularProgressIndicator();
                      return DropdownButton<UserModel>(
                        items: snapshot.data
                            .map((user) => DropdownMenuItem<UserModel>(
                                  child: Text(user.name),
                                  value: user,
                                ))
                            .toList(),
                        onChanged: (UserModel value) {
                          setState(() {
                            _currentUser = value;
                          });
                        },
                        isExpanded: true,
                        //value: _currentUser,
                        hint: Text('Select User'),
                      );
                    }),
                SizedBox(height: 20.0),
                _currentUser != null
                    ? Text(
                        "Name: " +
                            _currentUser.name +
                            "\n Email: " +
                            _currentUser.email +
                            "\n Username: " +
                            _currentUser.username +
                            "\n Password: " +
                            _currentUser.password,
                      )
                    : Text("No User selected"),
              ],
            ),
          ),
        );
      }
    }

下拉菜单不显示为选中的,它就像没有选中一样。请支持我解决问题

【问题讨论】:

  • 您已评论 - value: _currentUser, - 您将如何看待您看到的选定值。?

标签: flutter dart


【解决方案1】:

问题

1。下拉菜单需要选择可用选项

我们可以看到items参数,DropdownButton会得到它 选项定义

DropdownButton<UserModel>(
  items: snapshot.data // <-- this define options
      .map((user) => DropdownMenuItem<UserModel>(
            child: Text(user.name),
            value: user,
          ))
      .toList(),
  onChanged: (UserModel value) {
    setState(() {
      _currentUser = value;
    });
  },
  value: _currentUser,
);

2。如果包裹在 FutureBuilder 中,下拉菜单将重新初始化多次

问题发生在我们选择一个选项之后。 Dropdown会修改StatefulWidget中的_currentUser,执行setState

通过触发setState,默认情况下Flutter widget会再次触发build方法。

FutureBuilder<List<UserModel>>(
  future: db.getUserModelData(),
  builder: (BuildContext context, AsyncSnapshot snapshot) {
    if (!snapshot.hasData) return CircularProgressIndicator();
    return DropdownButton<UserModel>(
      items: snapshot.data
          .map((user) => DropdownMenuItem<UserModel>(
                child: Text(user.name),
                value: user,
              ))
          .toList(),
      onChanged: (UserModel value) {
        setState(() {
          _currentUser = value; // <-- Will trigger re-build on StatefulWidget
        });
      },
      value: _currentUser,
    );
}),


解决方案

1。解决方案:在 initState 中初始化选项一次

这对我们来说是强制性的,不要在构建方法中初始化。由于我们需要移除FutureBuilder,我们还需要初始化screenStage


@override
void initState() {
  _screenStage = "loading"; // <-- set "loading" to display CircularProgress
  onceSetupDropdown();
  super.initState();
}

void onceSetupDropdown() async {
  _userSelection = await db.getUserModelData();
  _screenStage = "loaded"; // <-- set "loaded" to display DropdownButton
  setState(() {}); // <-- trigger flutter to re-execute "build" method
}

2。然后我们就可以根据screenStage的值正确渲染了

这对我们来说是强制性的,不要在构建方法中初始化。 因此,我们可以移除 FutureBuilder

_screenStage == "loaded"
  ? DropdownButton<UserModel>(  // <-- rendered at second "build"
      items: _userSelection
          .map((user) => DropdownMenuItem<UserModel>(
                child: Text(user.name),
                value: user,
              ))
          .toList(),
      onChanged: onChange,
      isExpanded: true,
      value: _currentUser,
      hint: Text('Select User'),
    )
  : CircularProgressIndicator(), // <-- rendered at first "build"

结果


完整的工作代码

你可以在这个Github Repo查看它

【讨论】:

  • 刷新后显示错误另一个异常被抛出:'package:flutter/src/material/dropdown.dart':断言失败:第 608 行 pos 15:'items == null ||项目.isEmpty ||值 == 空 || items.where((DropdownMenuItem item) => item.value == value).length == 1': 不正确。
  • 然后你可以通过 snapshot.data 的第一个元素初始化它的值
  • 好的,我遇到了问题,这是因为我们在构建期间重新初始化了它的项目
  • 我已经添加了它们之间的详细解释和比较。您也可以通过访问上面提供的 repo 链接在本地构建它
  • @ejabu 唯一的解决方案,我发现它对我有用。
【解决方案2】:

在选择选择时尝试使用字符串而不是Usermodel。 字符串 _currentUser;

onChanged: (String value) {
                          setState(() {
                            _currentUser = value;
                          });
                        },

【讨论】:

  • 感谢Zeeshan,更改后显示错误参数类型'Null Function(String)'不能分配给参数类型'void Function(UserModel)'
  • @AmitNamdeo 请将 _currentUser 更改为字符串;
【解决方案3】:

因为您使用的是FutureBuilder,所以只需在onChanged 中删除setState()

onChanged: (UserModel value) {
 _currentUser = value;
}

【讨论】:

    【解决方案4】:

    @ejabu 的解释很有帮助,但我的代码似乎无法与他/她一样修改。

    顺便说一句,在小部件上调用加载和多次初始化的想法将导致重新初始化 DropdownButton 影响在颤动中不显示所选值。

    我对状态机有了一个概念,然后在我的状态类中简单地添加了一个布尔变量 isJustFinishedLoading = false。

    ...
    StreamBuilder<QuerySnapshot>(
    ...
    if(!snapshot.hasData){
    print('loading...');
    ...
    isJustFinishedLoading = true;
    }
    else
    {
    print('loaded');
    ...
        if (isJustFinishedLoading)
        {
           // initialize the DropdownMenuItem ...
        }
        return DropdownButton ... onChanged ...
    }
    

    希望对您有所帮助,2020 年新年快乐!

    【讨论】:

      猜你喜欢
      • 2020-06-30
      • 2020-01-24
      • 1970-01-01
      • 2023-01-08
      • 1970-01-01
      • 2021-10-26
      • 2019-12-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多