【问题标题】:Cannot change Dropdown button value Flutter无法更改下拉按钮值颤振
【发布时间】:2021-10-24 06:30:39
【问题描述】:

我想从 firebase 获取 Dropdown 按钮的初始值; 但是当我尝试在构建方法中设置governorateDDValue = selectedUser.governorate; Dropdown 的值从 firebase 获取值,但我无法更改它

DropdownButton.gif

这是我的代码

class UserInfo extends StatefulWidget {
  static const routeName = '/UserInfoScreen';

  const UserInfo({Key? key}) : super(key: key);

  @override
  _UserInfoState createState() => _UserInfoState();
}

class _UserInfoState extends State<UserInfo> {

  late User selectedUser;
  final date = DateFormat('yyyy-MM-dd').format(DateTime.now()).toString();

  var governorateDDValue;

  @override
  Widget build(BuildContext context) {

    final userList= Provider.of<List<User>>(context);
    final userID = ModalRoute.of(context)!.settings.arguments as String;
    selectedUser =
        userList.firstWhere((user) => user.id == userID);

    // this line makes dropdown value always equal to value from firestore
    governorateDDValue = selectedUser.governorate;

    return Scaffold(
      appBar: AppBar(
        title: Text('report'),
      ),
      body: SingleChildScrollView(
        child: Container(
          child: Row(
            children: <Widget>[
                    Text('Governorate',),
                    Container(height: 5),
                    DropdownButton<String>(
                      value: governorateDDValue,
                      icon: const Icon(Icons.arrow_downward),
                      iconSize: 24,
                      elevation: 16,
                      style: const TextStyle(color: Colors.deepPurple),
                      onChanged: (String? newValue) {
                        setState(() {
                          governorateDDValue = newValue!;
                        });
                      },
                      items: Constants.governoratesOfEgypt
                          .map<DropdownMenuItem<String>>((String value) {
                        return DropdownMenuItem<String>(
                          value: value,
                          child: Text(value),
                        );
                      }).toList(),
          ),
        ],
      ),
    ),
  ),
);

} }

提前致谢

【问题讨论】:

    标签: flutter google-cloud-firestore drop-down-menu dropdownbutton


    【解决方案1】:

    因为您在构建小部件中使用governorateDDValue = selectedUser.governorate;,所以每次更改下拉菜单时都会重置其值 构建小部件将重建,下拉列表的值将保持等于 firebase 的值 您应该在构建小部件之外使用governorateDDValue = selectedUser.governorate; 这段代码应该可以工作

    class UserInfo extends StatefulWidget {
      static const routeName = '/UserInfoScreen';
    
      const UserInfo({Key? key}) : super(key: key);
    
      @override
      _UserInfoState createState() => _UserInfoState();
    }
    
    class _UserInfoState extends State<UserInfo> {
    
      var loading = false;
    
      late User selectedUser;
      final date = DateFormat('yyyy-MM-dd').format(DateTime.now()).toString();
    
      var governorateDDValue;
    
    
      @override
      void initState() {
        super.initState();
        loading = true;
        print('Future.delayed outside');
        print(loading);
        Future.delayed(Duration.zero, () {
          governorateDDValue = selectedUser.governorate;
          setState(() {
            loading = false;
          });
        });
      }
    
    
      @override
      Widget build(BuildContext context) {
        final userList = Provider.of<List<User>>(context);
        final userID = ModalRoute
            .of(context)!
            .settings
            .arguments as String;
        selectedUser =
            userList.firstWhere((user) => user.id == userID);
    
        // this line makes dropdown value always equal to value from firestore
        governorateDDValue = selectedUser.governorate;
    
        return Scaffold(
          appBar: AppBar(
            title: Text('report'),
          ),
          body: SingleChildScrollView(
            child: Container(
              child: Row(
                children: <Widget>[
                  Text('Governorate',),
                  Container(height: 5),
                  DropdownButton<String>(
                    value: governorateDDValue,
                    icon: const Icon(Icons.arrow_downward),
                    iconSize: 24,
                    elevation: 16,
                    style: const TextStyle(color: Colors.deepPurple),
                    onChanged: (String? newValue) {
                      setState(() {
                        governorateDDValue = newValue!;
                      });
                    },
                    items: Constants.governoratesOfEgypt
                        .map<DropdownMenuItem<String>>((String value) {
                      return DropdownMenuItem<String>(
                        value: value,
                        child: Text(value),
                      );
                    }).toList(),
                  ),
                ],
              ),
            ),
          ),
        );
    

    【讨论】:

      【解决方案2】:

      之所以不能更改它是因为每次调用setState 时都会调用您的build 方法。因此,您的值将始终设置为 governorateDDValue = selectedUser.governorate; 所以要允许更改,您应该将此 governorateDDValue = selectedUser.governorate; 放在 iniState

      或者你可以这样做,这样它只会设置一次

      class UserInfo extends StatefulWidget {
        static const routeName = '/UserInfoScreen';
      
        const UserInfo({Key? key}) : super(key: key);
      
        @override
        _UserInfoState createState() => _UserInfoState();
      }
      
      class _UserInfoState extends State<UserInfo> {
      
        late User selectedUser;
        final date = DateFormat('yyyy-MM-dd').format(DateTime.now()).toString();
        bool initState = true; // ADD HERE
        var governorateDDValue;
      
        @override
        Widget build(BuildContext context) {
      
          final userList= Provider.of<List<User>>(context);
          final userID = ModalRoute.of(context)!.settings.arguments as String;
          selectedUser =
              userList.firstWhere((user) => user.id == userID);
      
          // this line makes dropdown value always equal to value from firestore
          if(initState){  // ADD HERE
          governorateDDValue = selectedUser.governorate; 
          initState = false;  // ADD HERE
          }
      
          return Scaffold(
            appBar: AppBar(
              title: Text('report'),
            ),
            body: SingleChildScrollView(
              child: Container(
                child: Row(
                  children: <Widget>[
                          Text('Governorate',),
                          Container(height: 5),
                          DropdownButton<String>(
                            value: governorateDDValue,
                            icon: const Icon(Icons.arrow_downward),
                            iconSize: 24,
                            elevation: 16,
                            style: const TextStyle(color: Colors.deepPurple),
                            onChanged: (String? newValue) {
                              setState(() {
                                governorateDDValue = newValue!;
                              });
                            },
                            items: Constants.governoratesOfEgypt
                                .map<DropdownMenuItem<String>>((String value) {
                              return DropdownMenuItem<String>(
                                value: value,
                                child: Text(value),
                              );
                            }).toList(),
                ),
              ],
            ),
          ),
        ),
      );
      }
      
      

      【讨论】:

      • 我把这个governanceDDValue = selectedUser.governorate;在 iniState 它给了我这个错误 LateInitializationError: Field 'selectedUser' has not been initialized。当我删除“selectedUser = userList.firstWhere((user) => user.id == userID);”到 initState 它给了我另一个错误在构建 Builder 时抛出了以下断言:在 _UserInfoState.initState() 完成之前调用了dependOnInheritedWidgetOfExactType<_modalscopestatus>() 或dependOnInheritedElement()。
      • 您必须将所有逻辑移动到 iniState 中,如果您需要提供者的上下文,您可以使用 didChangeDependencies
      • 我已经编辑了答案以获得更简单的解决方案
      猜你喜欢
      • 2021-07-30
      • 1970-01-01
      • 2018-11-23
      • 2020-03-14
      • 2021-11-24
      • 1970-01-01
      • 2023-02-13
      • 2022-11-08
      • 2021-04-22
      相关资源
      最近更新 更多