Ankit
Ankit

Reputation: 669

setState() not working properly in flutter

I have a question palette in the flutter screen, where a user taps on the question number that question is shown, and a next button to display the next question.

If I am traversing between the questions using the question palette it's working fine but when I click next button, it does not turn the question number on the palette to green(I want that question number to get green) and also it does not return the next question but the loop iterates. As after I press the button for some time, it says that there are no next questions as I have set this message when the loop ends.

Here is my code:

class quizpage extends StatefulWidget{

  var questions,surveyid;

  quizpage(this.questions,this.surveyid);

  //quizpage({Key key, @required this.questions}) : super(key : key);

  @override
  _quizpageState createState() => _quizpageState(questions,surveyid);
}

class _quizpageState extends State<quizpage> with SingleTickerProviderStateMixin {

  var questions,surveyid;




  _quizpageState(this.questions,this.surveyid);

  int i = 0;

  int flag = 0;
  int counter = 0;
  int length;



  Map<String, Color> btncolor = {
    "1" : Colors.grey,
    "2" : Colors.grey,
    "3" : Colors.grey,
    "4" : Colors.grey,
    "5" : Colors.grey,
    "6" : Colors.grey,
    "7" : Colors.grey,
    "8" : Colors.grey,
    "9" : Colors.grey,
  };



  final answercontroller = TextEditingController();



  @override
  Widget build(BuildContext context) {
    SystemChrome.setPreferredOrientations([
      DeviceOrientation.portraitDown, DeviceOrientation.portraitUp
    ]);
    SizeConfig().init(context);
    // TODO: implement build
    return Scaffold(
        body: SingleChildScrollView(
          scrollDirection: Axis.vertical,
          child: SizedBox(
            height: 600,
            child: Column(
              children: <Widget>[
                Expanded(
                  flex: 1,
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                    children: <Widget>[
                      Numberofquestion()
                    ],
                  ),
                ),
                Expanded(
                    flex: 4,
                    child: Center(
                      child: Container(
                        width: 400,
                        height: 400,
                        child: Column(
                          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                          children: <Widget>[
                            Container(
                              width: 250,
                              child: Material(
                                elevation: 5,
                                color: Colors.deepOrange,
                                borderRadius: BorderRadius.all(
                                    Radius.circular(10.0)),
                                child: TextField(
                                  enabled: false,
                                  maxLines: 6,
                                  decoration: InputDecoration(
                                      fillColor: Colors.white,
                                      filled: true,
                                      hintText: questions[i]
                                  ),
                                  style: TextStyle(
                                      fontSize: 20,
                                      color: Colors.black
                                  ),
                                ),
                              ),
                            )
                          ],
                        ),
                      ),
                    )
                ),
                Expanded(
                    flex: 2,
                    child: Center(
                        child: Container(
                            width: 300,
                            height: 300,
                            child: Column(
                                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                                children: <Widget>[
                                  Container(
                                    width: 250,
                                    child: Material(
                                      elevation: 2,
                                      color: Colors.deepOrange,
                                      borderRadius: BorderRadius.all(
                                          Radius.circular(10.0)),
                                      child: TextField(
                                        controller: answercontroller,
                                        maxLines: 1,
                                        //enabled: false,
                                        decoration: InputDecoration(
                                            fillColor: Colors.white,
                                            filled: true,
                                            hintText: 'Answer'
                                        ),
                                        style: TextStyle(
                                            fontSize: 20,
                                            color: Colors.black
                                        ),
                                      ),
                                    ),
                                  ),
                                ]
                            )
                        )
                    )
                ),
                Expanded(
                    flex: 2,
                    child: Align(
                      alignment: Alignment.topCenter,
                      child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: <Widget>[
                          Row(
                            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                            children: <Widget>[
                              RaisedButton(onPressed: SkipQuestion,
                                color: Colors.deepOrange,
                                textColor: Colors.white,
                                shape: RoundedRectangleBorder(
                                    borderRadius: BorderRadius.all(
                                        Radius.circular(10.0))),
                                child: Text('Skip',
                                  style: TextStyle(
                                      fontSize: 20
                                  ),
                                ),
                              ),
                              RaisedButton(onPressed: NextQuestion,
                                color: Colors.green,
                                textColor: Colors.white,
                                shape: RoundedRectangleBorder(
                                    borderRadius: BorderRadius.all(
                                        Radius.circular(10.0))),
                                child: Text('Next',
                                  style: TextStyle(
                                      fontSize: 20
                                  ),
                                ),
                              ),
                            ],
                          ),
                        ],
                      ),
                    )
                )
              ],
            ),
          ),
        ),
      ),
    );
  }

  @override
  void setState(fn) {
    // TODO: implement setState
    super.setState(fn);
    if(btncolor[(i+1).toString()] == Colors.deepOrange){
      btncolor[(i+1).toString()] = Colors.purple;
      flag = 1;
    }
    else if(btncolor[(i+1).toString()] == Colors.green){
      btncolor[(i+1).toString()] = Colors.purple;
      flag = 2;
    }
    else{
      btncolor[(i+1).toString()] = Colors.purple;
    }
  }

  void NextQuestion() async {
    if(answercontroller.text.length == 0){
      await showDialog(
        context: context,
        builder: (context) => new AlertDialog(
          title: new Text('Alert'),
          content: Text(
              'Please enter an answer.'),
          actions: <Widget>[
            new FlatButton(
              onPressed: () {
                Navigator.of(context, rootNavigator: true)
                    .pop(); // dismisses only the dialog and returns nothing
              },
              child: new Text('OK'),
            ),
          ],
        ),
      );
    }
    else{
      setState(() async {
        if(i < (questions.length - 1)){
          // ignore: unnecessary_statements
          btncolor[(i+1).toString()] = Colors.green;
          i++;
        }
        else{
          await showDialog(
            context: context,
            builder: (context) => new AlertDialog(
              title: new Text('Alert'),
              content: Text(
                  'There are no next questions.'),
              actions: <Widget>[
                new FlatButton(
                  onPressed: () {
                    Navigator.of(context, rootNavigator: true)
                        .pop(); // dismisses only the dialog and returns nothing
                  },
                  child: new Text('OK'),
                ),
              ],
            ),
          );
        }
      });

    }

  }


  @override
  void initState() {
    SystemChrome.setEnabledSystemUIOverlays([]);
    super.initState();
  }





  void SkipQuestion() {
    setState(() {
      if(i < (questions.length - 1)){
        // ignore: unnecessary_statements
        btncolor[(i+1).toString()] = Colors.deepOrange;
        i++;
      }
      else{
        Navigator.of(context).pushReplacement(MaterialPageRoute(
          builder: (context) => resultpage(surveyid),
        ));
      }
    });
  }



  void ChooseQuestion() {
    setState(() {
      if(i < (questions.length)){
        for(int k =0; k< (questions.length); k++){
          if(k != i){
            if(btncolor[(k+1).toString()] == Colors.purple){
              if(flag == 1){
                btncolor[(k+1).toString()] = Colors.red;
                flag =0;
              }
              else if(flag == 2){
                btncolor[(k+1).toString()] = Colors.green;
                flag =0;
              }
              else{
                btncolor[(k+1).toString()] = Colors.grey;
              }

            }
          }
          else{
            if(btncolor[(k+1).toString()] == Colors.purple){
              if(flag == 1){
                btncolor[(k+1).toString()] = Colors.red;
              }
              else if(flag == 2){
                btncolor[(k+1).toString()] = Colors.green;
                flag =0;
              }
              else{
                btncolor[(k+1).toString()] = Colors.grey;
              }
            }
          }
        }
        //i++;
      }
      else{
        Navigator.of(context).pushReplacement(MaterialPageRoute(
          builder: (context) => resultpage(surveyid),
        ));
      }
    });
  }

  Widget Numberofquestion() {
    if(questions.length == 9){
      return Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: <Widget>[
          Container(
            width: 40,
            padding: EdgeInsets.all(5),
            child: RaisedButton(onPressed: () {
              i = 0;
              ChooseQuestion();
            },
              color: btncolor["1"],
              textColor: Colors.white,
              shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.all(
                      Radius.circular(10.0))),
              child: Text("1",
                textAlign: TextAlign.center,
                style: TextStyle(
                    fontSize: 20
                ),
              ),
            ),
          ),
          Container(
            width: 40,
            padding: EdgeInsets.all(5),
            child: RaisedButton(onPressed: () {
              i = 1;
              ChooseQuestion();
            },
              color: btncolor["2"],
              textColor: Colors.white,
              shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.all(
                      Radius.circular(10.0))),
              child: Text('2',
                textAlign: TextAlign.center,
                style: TextStyle(
                    fontSize: 20
                ),
              ),
            ),
          ),
          Container(
            width: 40,
            padding: EdgeInsets.all(5),
            child: RaisedButton(onPressed: () {
              i = 2;
              ChooseQuestion();
            },
              color: btncolor["3"],
              textColor: Colors.white,
              shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.all(
                      Radius.circular(10.0))),
              child: Text('3',
                textAlign: TextAlign.center,
                style: TextStyle(
                    fontSize: 20
                ),
              ),
            ),
          ),
          Container(
            width: 40,
            padding: EdgeInsets.all(5),
            child: RaisedButton(onPressed: () {
              i = 3;
              ChooseQuestion();
            },
              color: btncolor["4"],
              textColor: Colors.white,
              shape: RoundedRectangleBorder(
                  borderRadius: BorderRadius.all(
                      Radius.circular(10.0))),
              child: Text('4',
                textAlign: TextAlign.center,
                style: TextStyle(
                    fontSize: 20
                ),
              ),
            ),
          ),
        ],
      );
    }
  }
}

Here, questions is the array which stores the question.

When I am using the 'Skip' button, the setState works perfectly but when I am using 'Next' button the setState is not working.

Can someone help me with this please?

Upvotes: 1

Views: 4730

Answers (2)

Falyoun
Falyoun

Reputation: 3966

I'd say that you're manipulating the state in a wrong way

As docs refers:

@protected
void setState (VoidCallback fn)

The provided callback is immediately called synchronously. It must not return a future (the callback cannot be async), since then it would be unclear when the state was actually being set.

things to note:

  • don't call setState() inside initState()
  • don't call setState() in synchronous code inside build()
  • setState() should run synchronously so new updates happen atomically
  • hence, try not to mark setState() as async

You might see the link, hope it's useful

Upvotes: 3

Taz
Taz

Reputation: 1971

try this

 @override
      void setState(fn) {
       
      
        if(btncolor[(i+1).toString()] == Colors.deepOrange){
          btncolor[(i+1).toString()] = Colors.purple;
          flag = 1;
        }
        else if(btncolor[(i+1).toString()] == Colors.green){
          btncolor[(i+1).toString()] = Colors.purple;
          flag = 2;
        }
        else{
          btncolor[(i+1).toString()] = Colors.purple;
        }
        super.setState(fn);//move here
      }

Upvotes: 1

Related Questions