我是flutter的新手,正在构建一个创建项目的应用程序。我正在开发查看项目页面,该页面允许用户查看每个问题。它的设置方式允许用户查看问题,然后单击"下一步"(同时保持在同一页面上(查看下一个问题。第一个initState初始化Project对象。然后,这个项目对象需要从文档中获取数据/信息。问题存储为问题对象列表,其中每个对象都有一个类型(文本、多选、数字、照片上传等(、问题和编号。问题类型用于确定要呈现哪个小部件(例如:照片上传将是与文本输入不同的形式(
我遇到的问题是,项目对象已初始化,但问题对象列表未初始化,并且我遇到索引错误。然而,当我热刷新时,我会看到正确的小部件(目前只是文本(。我认为与此相关的另一个问题是,每次用户单击下一个时,对象都会再次检索所有问题,因此列表永远不会结束。我相信问题出在getproject.dart中的getdataFromProject和questionData((函数中(第一个代码片段(。
我尝试过使用未来的生成器,但我不确定这是否是正确的解决方案。然而,我的构建确实取决于正在完成的对象。因此,我尝试使用一个变量Future projectFuture,并将其设置为等于我的_getQuestions((函数(在initState((中调用(。
感谢您的帮助。
class Questions {
final String question;
final String number;
final String type;
Questions({this.question, this.number, this.type});
List<String> answers = new List();
}
class GetProject {
//this is what keeps growing each time next is pressed
List<Questions> questions; //holds the question objects
String docID;
String title;
GetProject(String title, String docID){
this.docID = docID;
this.title=title;
questionData();
}
Future<void> get getdataFromProject async {
return await questionData();
}
Future<void> questionData() async {
int count = 0;
Future<DocumentSnapshot> snapshot =
Firestore.instance.collection('Projects').document(this.docID).get();
return await snapshot.then((DocumentSnapshot questionSnap) => {
questionSnap.data.forEach((key, value) {
if ('$key' == 'count') {
count = value;
count--;
//returncount=count;
} else if ('$key' == ('Question' + count.toString())) {
print(value['Type']);
Questions question = new Questions(
type: value['Type'],
number: value['Number'],
question: value['Question'],
);
if (value['Type'] == 'MultipleChoice') {
value['Answers'].forEach((e) {
question.answers.add(e.toString());
});
//question.answers.addAll(value['Answers']);
}
questions.add(question);
count--;
}
}),
});
}
int getType(int index) {
switch (questions[index].type) {
case 'TextInputItem':
return 0;
case 'MultipleChoice':
return 1;
case 'ShortAnswerItem':
return 2;
case 'UserLocation':
return 3;
}
return -1;
}
class ViewProject extends StatefulWidget {
final String docIDref;
final String title;
ViewProject({this.docIDref, this.title});
@override
_ViewProjectState createState() => _ViewProjectState();
}
class _ViewProjectState extends State<ViewProject> {
GetProject project;
int _currentQuestion = 0;
Future projectFuture;
int _getType(_currentQuestion) {
switch(project.questions[_currentQuestion].type){
case 'TextInputItem':
return 0;
case 'MultipleChoice':
return 1;
case 'ShortAnswerItem':
return 2;
case 'UserLocation':
return 3;
}
return -1;
}
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: AppBar(title: Text("Random Widget")),
body:
project.questions.length == 0
? Center(child: CircularProgressIndicator()
)
:
Center(child:
FutureBuilder(
initialData: 0,
future: projectFuture,
builder: (context, snapshot) {
if(project.questions.length>0){
return getQuestionWidget();
}
else{
return CircularProgressIndicator();
}
}
)
)),
);
}
Widget getQuestionWidget() {
switch(_getType(_currentQuestion++)){
case 0:
return Column(children: <Widget>[
Text("TextInputItem", textScaleFactor: 4),
getNextButton()
]);
break;
case 1:
return Column(children: <Widget>[
Text("MultipleChoice", textScaleFactor: 4),
getNextButton()
]);
break;
case 2:
return Column(children: <Widget>[
Text("ShortAnswer", textScaleFactor: 4),
getNextButton()
]);
break;
case 3:
return Column(children: <Widget>[
Text("UserLocation", textScaleFactor: 4),
getNextButton()
]);
break;
case -1:
return Column(children: <Widget>[
Text("Submit Page", textScaleFactor: 4),
//getNextButton()
]);
}
}
Widget getNextButton(){
return RaisedButton(
child: Text("NEXT"),
color: Colors.red,
onPressed: () {
if(_currentQuestion < project.questions.length){
return getQuestionWidget();
}
return Text("All done!");
//setState(() {
//_currentQuestion++;
//return getQuestionWidget();
//_getType(_currentQuestion);
// });
}
);
}
@override
void initState() {
project = new GetProject(widget.title, widget.docIDref);
//project.getdataFromProject();
//_getQuestions();
projectFuture=_getQuestions();
super.initState();
}
Future<void> _getQuestions() async {
return await project.getdataFromProject;
}
// Call this function when you want to move to the next page
void goToNextPage() {
_currentQuestion++;
}
}
我通常在didChangeDependencies方法中加载期货。
类似于:-
@override
didChangeDependencies() {
if (this.asyncdata == null)
loadData();
}
Future<void> loadData() async {
this.asyncdata = await someAsyncFuntionThatReturnsData();
}
这应该会有所帮助。在按下按钮的那一天加载东西总是更容易,因为这些函数可以是异步期货,但上面的模式应该也能解决if的双重加载问题。
我会为每个元素使用一个单独的小部件,并在initState中加载数据。