Reputation: 31
I'm making a question answer application to pass time.
There are questions in a question list. The code below shows for each question. A question can have multiple choices but only 1 answer.
I'm having trouble where everytime I type in the TextFormField, the cursor resets to the beginning. How can i avoid that? I need to use setState so that the Text Widget updates in realtime.
class Question{
int answer;
List<Answer> answers;
}
class Answer{
int index;
String answer;
}
class EditQuestionWidget extends StatefulWidget {
final List<Question> questions;
final int index;
EditQuestionWidget(this.questions, this.index);
@override
_EditQuestionWidgetState createState() => _EditQuestionWidgetState();
}
class _EditQuestionWidgetState extends State<EditQuestionWidget> {
@override
Widget build(BuildContext context) {
return Card( //For Each Question
child: ExpansionTile(
title: Text(widget.questions[widget.index].answer != null ? widget.questions[widget.index].answers[widget.questions[widget.index].answer].answer ?? 'Untitled Answer' : 'Untitled Answer'),
children: <Widget>[
ListView.builder( //For Each answer choice
itemCount: widget.questions[widget.index].answers.length,
itemBuilder: (context, i) {
TextEditingController answerController = TextEditingController(text: widget.questions[widget.index].answers[i].answer);
return Row(
children: <Widget>[
Expanded(
child: RadioListTile( //Select Answer
value: widget.questions[widget.index].answers[i].index,
groupValue: widget.questions[widget.index].answer,
onChanged: (int value) => setState(() => widget.questions[widget.index].answer = value),
title: TextFormField( //change answer choice text
controller: answerController,
onChanged: (text) {
setState(() {widget.questions[widget.index].answers[i].answer = text;}); // The cursor returns to beginning after executing this.
},
),
),
),
IconButton( //Remove Answer Function
onPressed: () {
//This method Works as intended.
if (widget.questions[widget.index].answers[i].index == widget.questions[widget.index].answer) widget.questions[widget.index].answer = null;
String answer = widget.questions[widget.index].answer != null ? widget.questions[widget.index].answers[widget.questions[widget.index].answer].answer : '';
widget.questions[widget.index].answers.remove(widget.questions[widget.index].answers[i]);
if (widget.questions[widget.index].answers.isEmpty) {
widget.questions[widget.index].answer = widget.questions[widget.index].answers.length;
widget.questions[widget.index].answers.add(new Answer(index: widget.questions[widget.index].answers.length));
}
for (int ii = 0; ii < widget.questions[widget.index].answers.length; ii++) {
widget.questions[widget.index].answers[ii].index = ii;
if (widget.questions[widget.index].answer != null && answer == widget.questions[widget.index].answers[ii].answer) widget.questions[widget.index].answer = ii;
}
setState(() {});
},
),
],
);
},
),
],
),
);
}
}
Upvotes: 3
Views: 1054
Reputation: 3469
You're updating the value of answerController every time the text changes, and when this update happens the cursor goes to the beginning.
To solve that you can create a list of TextEditingControllers outside the builder:
List<TextEditingController> controllers = [];
And then add a new Controller to the list when a new field is created:
itemBuilder: (context, i) {
if(controllers.length != widget.questions[widget.index].answers.length){
controllers.add(TextEditingController()); //condition to prevent the creation of infinity Controllers
}
And finally pass the controller to the TextField:
controller: controllers[i],
Upvotes: 1