gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-05 00:54:31 28 4
gpt4 key购买 nike

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

我有 3 个文件:

questionnaire.dartquestionnnaire_controller.dartpopup.dart

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

questionnaire.dart 中,我有代码显示要回答的问卷的弹出窗口的内容。

questionnaire_controller.dart 中,我使用了一些变量和函数,例如异步获取问卷数据的函数 getQuestionnaires() 或列表 questionnaires,或一个变量selectedQuestionnaire,用于保存已选择的问卷实例。

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

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,
);
});
}
}
}

如您所见,在 obx 中,我得到了 selectedQuestionnaireTitle 的值,这是一个存在于 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,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: TextSize.TEXT_LARGE,
fontWeight: FontWeight.w600,
color: EnvironmentVariables.mainColor,
),
),
// Text("no_data".tr),
SizedBox(
height: 32,
)
],
);
}
}),
),
);
}

您可以在上面的代码中看到一个名为 Dropdown 的小部件。这是我创建的有状态小部件。这个小部件也存在于 questionnaire.dart 中。 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,
color: EnvironmentVariables.mainColor,
),
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(),
);
}
}

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

The following assertion was thrown building Dropdown(dirty, state: _DropdownState#97b88):setState() or markNeedsBuild() called during build.

This Obx widget cannot be marked as needing to build because theframework is already in the process of building widgets. A widget canbe marked as needing to be built during the build phase only if one ofits ancestors is currently building. This exception is allowed becausethe framework builds parent widgets before children, which means adirty descendant will always be built. Otherwise, the framework mightnot visit this widget during this build phase. The widget on whichsetState() or markNeedsBuild() was called was: Obx state:_ObxState#d84a8 The widget which was currently being built when the offending call was made was: Dropdown dirty state:_DropdownState#97b88 The relevant error-causing widget was: Dropdown

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

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

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

感谢您的宝贵时间

最佳答案

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

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

需要知道的:

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

关于Flutter:在构建期间调用 setState() 或 markNeedsBuild()。使用 future builder 和 obx,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66100385/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com