Flutter:在构建期间调用 setState() 或 markNeedsBuild()使用 future builder 和 obx

问题描述

我正在使用 flutter 和 GetX,所以我在我的代码中实现了 Obx

我有 3 个文件:

questionnaire.dart questionnnaire_controller.dart popup.dart

popup.dart 内,我有弹出窗口的布局。

questionnaire.dart 中,我有一个代码,用于显示一个弹出窗口的内容,该弹出窗口显示待回答的问卷。

questionnaire_controller.dart里面我有一些变量和函数被使用,比如异步获取问卷数据的函数getQuestionnaires(),或者列表questionnaires,或者一个变量{{1 }} 保存已选择的问卷实例。

selectedQuestionnaire 中,如果已选择问卷,我必须在弹出对话框的顶部显示问卷的标题。部分代码如下:

popup.dart

如您所见,在 obx 中,我获得了 selectedQuestionnaireTitle 的值,这是一个存在于 static Future<void> showQuestionnaireInput({String title,Widget child,Widget icon}) async { bool mobileSize = Get.size.width <= ResponsiveSizingConfig.instance.breakpoints.desktop; if (mobileSize) { await Get.to(InputScreenWidget(child,title)); } else { await showDialog( context: Get.context,builder: (context) { return AlertDialog( titlePadding: EdgeInsets.all(8),contentPadding: EdgeInsets.all(8),title: Container( decoration: BoxDecoration(border: Border(bottom: BorderSide(color: Colors.grey.shade200,width: 2))),child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween,children: [ Padding( padding: EdgeInsets.only(left: 4),child: Row( children: [ if (icon != null) icon,if (icon != null) SizedBox(width: 4),Text(title),Obx(() { if(questionnaireController.selectedQuestionnaireTitle.value != '') return Text(questionnaireController.selectedQuestionnaireTitle.value); else return Container(); }),],),CloseButton( onPressed: () { Get.back(); },) ],content: child,); }); } } } 中的变量。

questionnnaire_controller.dart 中,我有一个 questionnaire.dart,用于提供我的问卷数据,以便用户通过下拉列表选择其中之一,然后点击下一步回答相应的问题。对我们的案例有用的部分代码如下:

future builder

您可以在上面的代码中看到一个名为 child: Obx(() { if (questionnaireController.questionnaireState.value == QuestionnaireController.QUESTIONNAIRE_CHOOSE) { return Container( width: screenWide ? Get.size.width * 0.5 : Get.size.width * 1,child: Center( child: FutureBuilder( future: questionnaireController.getQuestionnaires(),builder: (context,snapshot) { questionnaireController.dialIsBuilt.value = true; print(questionnaireController.dialIsBuilt.value); switch (snapshot.connectionState) { case ConnectionState.waiting: questionnaireController.dialIsBuilt.value = false; print(questionnaireController.dialIsBuilt.value); return CircularProgressIndicator(); default: if (snapshot.hasData) { print(questionnaireController.dialIsBuilt.value); return Column( children: [ Text( 'choose_questionnaire'.tr,textAlign: TextAlign.center,style: TextStyle( fontSize: TextSize.TEXT_LARGE,fontWeight: FontWeight.w600,color: EnvironmentVariables.mainColor,SizedBox( height: 8,Dropdown( questionnaires: questionnaireController.questionnaires,selectedQuestionnaire: questionnaireController.selectedQuestionnaire,Obx( () { if (questionnaireController.buttonDisplay.value == true) { return Container( margin: EdgeInsets.all(16),child: defaultButton( text: 'next_question'.tr,onPressed: () { questionnaireController.answerQuestionnaire(); },); } else { return Container(); } },); } else return Column( children: [ Text( 'choose_questionnaire'.tr,// Text("no_data".tr),SizedBox( height: 32,) ],); } }),); } 的小部件。这是我创建的一个有状态小部件。这个小部件也存在于 Dropdown 中。 questionnaire.dart 的代码如下。

Dropdown

当我运行代码并打开弹出对话框时,出现以下错误

构建 Dropdown(dirty,state: _DropdownState#97b88) 时抛出以下断言: 在构建期间调用 setState() 或 markNeedsBuild()。

无法将此 Obx 小部件标记为需要构建,因为 框架已经在构建小部件的过程中。一个小部件可以 仅在以下情况之一时才被标记为需要在构建阶段构建 它的祖先目前正在建造。允许此异常是因为 该框架在子级之前构建父级小部件,这意味着 肮脏的后代将永远被建立。否则,框架可能 在此构建阶段不要访问此小部件。其上的小部件 setState() 或 markNeedsBuild() 被调用为: Obx 状态: _ObxState#d84a8 发出违规调用时当前正在构建的小部件是:下拉脏状态: _DropdownState#97b88 相关的导致错误的小部件是:Dropdown

我的问题是,我该如何解决这个错误?我知道以下功能会有所帮助

class Dropdown extends StatefulWidget {
  final List questionnaires;
  final Questionnaire selectedQuestionnaire;

  Dropdown({
    this.questionnaires,this.selectedQuestionnaire,});

  @override
  _DropdownState createState() => _DropdownState(
        questionnaires: questionnaires,// dropdownValue: selectedQuestionnaire.title,);
}

class _DropdownState extends State<Dropdown> {
  List questionnaires;
  String dropdownValue = questionnaireController.selectedQuestionnaire.title;

  _DropdownState({
    this.questionnaires,// this.dropdownValue,});

  @override
  Widget build(BuildContext context) {
    questionnaireController.setSelectedQuestionnaire(questionnaireController.selectedQuestionnaire);
    return DropdownButton(
      isExpanded: true,value: dropdownValue,icon: Icon(Icons.arrow_downward),iconSize: 24,elevation: 16,style: TextStyle(color: EnvironmentVariables.mainColor,fontSize: TextSize.TEXT_SMALL),underline: Container(
        height: 1.6,onChanged: (newValue) {
        widget.questionnaires.forEach((questionnaire) {
          if (questionnaire.title == newValue) {
            questionnaireController.setSelectedQuestionnaire(questionnaire);
            // questionnaireController.selectedQuestionnaire = questionnaire;
          }
        });
        Future.delayed(Duration(seconds: 5),() => setState(() {
          dropdownValue = questionnaireController.selectedQuestionnaire.title;
        }));


        //Show continue button
        questionnaireController.showButton();

        //Used in reminder
      },items: widget.questionnaires.map((questionnaire) {
        return DropdownMenuItem(
          value: questionnaire.title,child: Text(
            questionnaire.title,style: TextStyle(color: EnvironmentVariables.secondaryColor),);
      }).toList(),);
  }
}

但是我应该在哪里实现上述功能?

感谢您的时间

解决方法

如果您使用 Statefull 小部件,您可以在 initState 内进行初始化

initState(){
 super.initState();
  WidgetsBinding.instance.addPostFrameCallback((_) {
  // executes after build
  });
}

需要知道:

  1. addPostFrameCallback 将在构建调用完成后触发

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...