It is best if you use PageView
for a dynamic survey form. First, it provides you with animation which comes in handy. Secondly, even if you remove or add children of the PageView
, it will not be throwing you an error, instead, it will help you navigate to the previous page.
Here I make a snippet for your use case. Based on the question, there is a lot of probability depending on the answer. My answer will not cover all the use cases, however, you can customize QuestionModel
to suit your needs.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final PageController _pageController = PageController();
List<QuestionModel> _questions = [
QuestionModel(
question: 'Is elephant big?',
questionType: QuestionType.MultipleChoice,
answerList: ['yes', 'no'],
isCorrect: false,
displayDependsOnAnswerOfIndex: null,
navigateToIndexIfCorrect: 1,
questionAction: (answer) {
if (answer == 'yes') {
return true;
} else {
return false;
}
}),
QuestionModel(
question: 'If big, state the height in feet.',
questionType: QuestionType.Form,
answerList: [],
isCorrect: false,
displayDependsOnAnswerOfIndex: 0,
navigateToIndexIfCorrect: null,
questionAction: (answer) {
if (answer != null) {
return true;
} else {
return false;
}
}),
];
@override
void dispose() {
_pageController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
List<QuestionModel> questions = _questions.where((questionModel) {
if (questionModel.displayDependsOnAnswerOfIndex != null) {
return (_questions[questionModel.displayDependsOnAnswerOfIndex]
.isCorrect);
} else {
return true;
}
}).toList();
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: Scaffold(
appBar: AppBar(
title: Text('Survey'),
),
body: PageView(
controller: _pageController,
children: questions.map((questionModel) {
if (questionModel.questionType == QuestionType.MultipleChoice) {
return Scaffold(
body: Column(
children: [
Text(questionModel.question),
Column(
children: questionModel.answerList.map((answer) {
return ListTile(
title: Text(
answer,
style: TextStyle(
fontWeight:
(answer == questionModel.choosenAnswer)
? FontWeight.bold
: FontWeight.normal,
),
),
onTap: () {
setState(() {
questionModel.choosenAnswer = answer;
questionModel.isCorrect =
questionModel.questionAction(answer);
});
if (questionModel.navigateToIndexIfCorrect !=
null &&
questionModel.isCorrect) {
_pageController.animateToPage(
questionModel.navigateToIndexIfCorrect,
duration: Duration(seconds: 1),
curve: Curves.easeInOut,
);
}
});
}).toList(),
),
],
),
);
} else if (questionModel.questionType == QuestionType.Form) {
return Scaffold(
//TODO: create implementation of form type question
body: Column(
children: [TextFormField()],
),
);
} else {
return Container();
}
}).toList(),
),
),
);
}
}
enum QuestionType {
MultipleChoice,
Form,
}
class QuestionModel {
final String question;
bool isCorrect;
String choosenAnswer;
final List<String> answerList;
final QuestionType questionType;
final int displayDependsOnAnswerOfIndex;
final int navigateToIndexIfCorrect;
final Function questionAction;
QuestionModel({
this.question,
this.choosenAnswer,
this.questionType,
this.answerList,
this.isCorrect,
this.navigateToIndexIfCorrect,
this.displayDependsOnAnswerOfIndex,
this.questionAction,
});
}