Flutter中下拉按钮未显示已选择的值

5

我是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"),
              ],
            ),
          ),
        );
      }
    }

下拉菜单没有显示所选项,它仍然保持着好像没有选择任何东西一样。请支持我解决这个问题。


2
你已经在注释中写道 - value: _currentUser, - 你将如何查看所选的值? - anmol.majhail
4个回答

7

问题

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. 如果将Dropdown包装在FutureBuilder中,它会多次重新初始化

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

通过触发setState, 默认情况下Flutter小部件将再次触发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中初始化选项

对于我们而言,不要在build方法中进行初始化。因为我们需要删除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的值来正确呈现

对我们来说,不要在build方法内初始化是必需的。因此,我们可以移除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位置15:'items == null || items.isEmpty || value == null || items.where((DropdownMenuItem<T> item) => item.value == value).length == 1':不是真实的。 - Amit Namdeo
然后,您可以通过快照数据的第一个元素来初始化其值。 - ejabu
好的,我明白问题了,这是因为我们在构建过程中重新初始化了它的项目。 - ejabu
我已经添加了详细的解释和比较。您还可以通过访问上面提供的存储库链接来本地构建它。 - ejabu
@ejabu 我找到的唯一解决方案,对我非常有用。 - Tarun Sharma

1
尝试在选择时使用String而不是UserModel来更改值。 String _currentUser;
onChanged: (String value) {
                          setState(() {
                            _currentUser = value;
                          });
                        },

谢谢Zeeshan, 更改后出现错误参数类型“Null Function(String)”无法分配给参数类型“void Function(UserModel)” - Amit Namdeo
@AmitNamdeo,请把_currentUser改成String类型; - Zeeshan Ansari

0
由于您正在使用FutureBuilder,因此只需在onChanged中删除setState():
onChanged: (UserModel value) {
 _currentUser = value;
}

-2

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

顺便说一下,在Flutter中,加载和多次初始化的想法会导致重新初始化DropdownButton,从而不显示选定的值。

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

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接