【问题标题】:Flutter - calling setState() before the buildFlutter - 在构建之前调用 setState()
【发布时间】:2021-12-21 10:14:27
【问题描述】:

我使用 futureBuilder 在 TextFormFields 中显示日期,如果我在 futureBuilder 中为我在 DateTimePicker 中选择的日期调用的 web 服务中有数据,则 TextFormField 被禁用并在其中显示数据。否则,启用 textFormField。

我还有一个按钮,如果收到数据,我想禁用它,如果没有,我想启用它,所以我使用了一个布尔值。

这是我的代码:

child: FutureBuilder<double?>(
                                  future: getTimes(selectedDate),
                                  builder: (BuildContext context, AsyncSnapshot snapshot) {
                                    if (snapshot.hasData){
                                      _timeController.clear();
                                        setState(() {
                                          _isButtonDisabled = false;
                                        });
                                      return TextFormField(
                                        controller: _timeController,
                                        textAlign: TextAlign.center,
                                        enabled: false,
                                        decoration: InputDecoration(
                                          hintText: snapshot.data.toString() + " h",
                                          contentPadding: EdgeInsets.zero,
                                          filled: true,
                                          fillColor: Colors.white70
                                        ),
                                      );
                                    } 
                                    else {
                                        setState(() {
                                          _isButtonDisabled = true;
                                        });
                                      return TextFormField(
                                        controller: _timeController,
                                        textAlign: TextAlign.center,
                                        enabled: true,
                                        decoration: InputDecoration(
                                          hintText: "0 h",
                                          contentPadding: EdgeInsets.zero,
                                          filled: true,
                                          fillColor: Colors.white
                                        ),
                                      );
                                    }
                                  }
                                )

这导致我在构建期间调用了错误 setState() 或 markNeedsBuild,因此感谢this topic 的回答,我将 setState 方法封装在 WidgetsBinding.instance.addPostFrameCallback(( _)

这是我的代码现在的样子:

child: FutureBuilder<double?>(
                                  future: getTimes(selectedDate),
                                  builder: (BuildContext context, AsyncSnapshot snapshot) {
                                    if (snapshot.hasData){
                                      _timeController.clear();
                                      WidgetsBinding.instance?.addPostFrameCallback((_){
                                        setState(() {
                                          _isButtonDisabled = false;
                                        });
                                      });
                                      return TextFormField(
                                        controller: _timeController,
                                        textAlign: TextAlign.center,
                                        enabled: false,
                                        decoration: InputDecoration(
                                          hintText: snapshot.data.toString() + " h",
                                          contentPadding: EdgeInsets.zero,
                                          filled: true,
                                          fillColor: Colors.white70
                                        ),
                                      );
                                    } 
                                    else {
                                      WidgetsBinding.instance?.addPostFrameCallback((_){
                                        setState(() {
                                          _isButtonDisabled = true;
                                        });
                                      });
                                      return TextFormField(
                                        controller: _timeController,
                                        textAlign: TextAlign.center,
                                        enabled: true,
                                        decoration: InputDecoration(
                                          hintText: "0 h",
                                          contentPadding: EdgeInsets.zero,
                                          filled: true,
                                          fillColor: Colors.white
                                        ),
                                      );
                                    }
                                  }
                                )

我现在遇到的问题是我的 TextFormFields 不再可点击,并且按钮始终处于启用状态,可能是误用/误解了 addPostFrameCallback 函数。

感谢您的帮助,

【问题讨论】:

    标签: flutter dart future setstate flutter-futurebuilder


    【解决方案1】:

    你有DateTimePicker,在选择日期时间后你可以调用未来。

    getTimes() 返回可为空的双精度。重调数据前,比较值是否为空,并据此设置_isButtonDisabled,赋值true/false

     bool _isButtonDisabled = true; // set the intial/watting state you want
    
     Future<double?> getTimes(DateTime time) async {
        //heavy operations
        return await Future.delayed(Duration(seconds: 3), () {
          return 4; //check with null +value
        });
      }
    
    ----
     @override
      Widget build(BuildContext context) {
        print("rebuild");
        return Column(
          children: [
            ElevatedButton(
              onPressed: () async {
                final selectedDate = await showDatePicker(
                  context: context,
                  initialDate: DateTime.now(),
                  firstDate: DateTime.now().subtract(Duration(days: 4444)),
                  lastDate: DateTime.now().add(Duration(days: 4444)),
                );
    
                if (selectedDate == null) return;
    
                final response = await getTimes(selectedDate);
    
                print(response);
                setState(() {
                  _isButtonDisabled = response != null;
                });
              },
              child: Text("Select Date"),
            ),
            ElevatedButton(
                onPressed: _isButtonDisabled ? null : () {}, child: Text("t"))
          ],
        );}
    

    【讨论】:

    • 感谢您的回答,我试过了,但是在函数中使用 setState 会创建一个无限循环,我猜是因为 FutureBuilder 总是调用这个函数来构建小部件
    • 我已经根据对话更新了答案,是否解决了您的问题?
    猜你喜欢
    • 1970-01-01
    • 2020-12-12
    • 2020-12-28
    • 2021-01-06
    • 2021-05-31
    • 2021-08-24
    • 2020-08-11
    相关资源
    最近更新 更多