有状态的小部件不更新,在setState中更新后,该如何解决?

时间:2019-09-04 09:10:53

标签: flutter state

我是Flutter的新手。我正在尝试构建测验应用程序。现在,我在测验屏幕上,然后一个测验中有多个问题。我将显示问题标题和答案,当有人单击答案时,我将使用新的问题数据再次更新QuestionView。这些是有状态的小部件,获取结果时,我使用setState更新小部件,如果在该处放置断点,则可以看到事物已更新,但未在屏幕上呈现或该视图未更改,它具有相同的标题,答案和所有内容。我正在使用optionTap方法,您可以在下面的评论中找到它。我已经提到了我点击该选项的位置以及它下面的操作。

这是我到目前为止所做的:

import 'package:flutter/material.dart';
import 'package:flutter_app/Constants/constants.dart';
import 'package:flutter_app/Models/question_model.dart';
import 'package:flutter_app/ViewModels/QuestionsVM.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';

QuizQuestionViewModel questionViewModel = QuizQuestionViewModel();

QuizQuestionModel _questionModel;
Widget updateWidget;

class SQQuiz extends StatefulWidget {
  final QuizQuestionModel quizQuestionModel;
  final int quizId;

  SQQuiz({Key key, @required this.quizQuestionModel, @required this.quizId})
      : super(key: key);
  @override
  _SQQuizState createState() =>
      _SQQuizState(quizQuestionModel: quizQuestionModel, quizId: quizId);
}

class _SQQuizState extends State<SQQuiz> {
  final QuizQuestionModel quizQuestionModel;
  final int quizId;

  _SQQuizState(
      {Key key, @required this.quizQuestionModel, @required this.quizId});

  @override
  Widget build(BuildContext context) {
    _questionModel = quizQuestionModel;
    updateWidget = QuestionView(
      quizQuestionModel: _questionModel,
      quizId: quizId,
    );
    return Scaffold(
      appBar: AppBar(
        leading: Container(
          child: Row(
            children: <Widget>[
              IconButton(
                onPressed: () {
                  Navigator.pop(context);
                },
                icon: Icon(Icons.arrow_back),
              ),
            ],
          ),
        ),
        title: Padding(
          padding: const EdgeInsets.symmetric(horizontal: 0),
          child: Container(
            child: Row(
              mainAxisAlignment: MainAxisAlignment.start,
              children: <Widget>[
                Text(
                  _questionModel.questionDetail.quizName,
                  style: TextStyle(color: Constants.greyColor, fontSize: 12),
                  textAlign: TextAlign.left,
                ),
                SizedBox(
                  width: 14,
                ),
                CircularProgressIndicator(
                  value: 15,
                  strokeWidth: 2,
                ),
              ],
            ),
          ),
        ),
        actions: <Widget>[
          Container(
            margin: const EdgeInsets.only(right: 10),
            child: Center(
              child: Container(
                child: Text("SCORE ${_questionModel.score}"),
              ),
            ),
          )
        ],
      ),
      body: SafeArea(child: updateWidget),
    );
  }
}

class QuestionView extends StatefulWidget {
  final QuizQuestionModel quizQuestionModel;
  final int quizId;

  QuestionView(
      {Key key, @required this.quizQuestionModel, @required this.quizId})
      : super(key: key);

  @override
  _QuestionViewState createState() => _QuestionViewState(
        quizQuestionModel: quizQuestionModel,
        quizId: quizId,
      );
}

class _QuestionViewState extends State<QuestionView> {
  final QuizQuestionModel quizQuestionModel;
  final int quizId;

  _QuestionViewState({@required this.quizQuestionModel, @required this.quizId});

  @override
  Widget build(BuildContext context) {
    QuestionDetail questionDetail = quizQuestionModel.questionDetail;

    return Column(
      mainAxisSize: MainAxisSize.min,
      children: <Widget>[
        Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            SizedBox(
              height: 10,
            ),
            Text(
              "Question ${quizQuestionModel.count}/${quizQuestionModel.totalCount}",
              style: TextStyle(fontSize: 12),
            ),
            SizedBox(
              height: 5,
            ),
            Image(
              image: NetworkImage(
                questionDetail.pic,
              ),
              fit: BoxFit.cover,
            ),
            Container(
              padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 50),
              color: Constants.orangeColor,
              child: Text(
                questionDetail.title,
                style: TextStyle(
                  color: Colors.white,
                  fontSize: 16,
                ),
                textAlign: TextAlign.center,
              ),
            ),
            ListView.builder(
              itemBuilder: (context, index) {
                Answers answers = questionDetail.answers[index];
                return Card(
                  elevation: 5,
                  margin:
                      const EdgeInsets.symmetric(vertical: 10, horizontal: 0),
                  child: ListTile(
                    onTap: () { //This is where I am tapping the option
                      optionTap(
                        context: context,
                        sessionId: quizQuestionModel.sessionId,
                        quizId: quizId,
                        questionId: questionDetail.questionId,
                        answerId: answers.id,
                        hintUsed: false,
                        fiftyUsed: false,
                      ).then((response) {
                        setState(() { //Here the updateWidget is updated, which you can see in the body, but it is not rendered
                          _questionModel = response;
                          updateWidget = new QuestionView(
                            quizQuestionModel: response,
                            quizId: quizId,
                          ); // The new QuestionView with new details
                        });
                      });
                    },
                    contentPadding: const EdgeInsets.symmetric(vertical: 10),
                    title: Text(
                      answers.title,
                      textAlign: TextAlign.center,
                    ),
                  ),
                );
              },
              itemCount: questionDetail.answers.length,
              physics: NeverScrollableScrollPhysics(),
              shrinkWrap: true,
            ),
            SizedBox(
              height: 20,
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                RaisedButton(
                  padding: const EdgeInsets.symmetric(horizontal: 50),
                  shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(5),
                  ),
                  onPressed: () {
                    print("50-50 Tapped");
                  },
                  child: Text(
                    "50 | 50\n ${quizQuestionModel.fiftyCoin} coins",
                    textAlign: TextAlign.center,
                    style: TextStyle(
                      color: Colors.white,
                    ),
                  ),
                ),
                Wrap(
                  spacing: 3,
                  children: <Widget>[
                    Icon(FontAwesomeIcons.coins),
                    Text("${quizQuestionModel.coins}"),
                  ],
                ),
                RaisedButton(
                  padding: const EdgeInsets.symmetric(horizontal: 50),
                  shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(5),
                  ),
                  onPressed: () {
                    print("Hint Tapped");
                  },
                  child: Text(
                    "HINT\n ${quizQuestionModel.hintUsed} coins",
                    textAlign: TextAlign.center,
                    style: TextStyle(
                      color: Colors.white,
                    ),
                  ),
                )
              ],
            ),
          ],
        )
      ],
    );
  }

目前没有错误,有人可以帮助我吗?预先感谢。

1 个答案:

答案 0 :(得分:0)

没有冒犯-但是我认为您完全误解了状态管理的概念。

如果您有状态的小部件,则setState()方法将再次触发build()方法。因此setState是一个通知者:嘿,我们的变量有一个更新,请重新构建。

您的有状态小部件正在执行此操作。但是该小部件上的变量没有新的更新,因为您的变量不在小部件内。他们不会为您的StatefulWidget更新。考虑重新考虑您的体系结构。对于小型Apps,在构造函数中传递变量就足够了。

这里有一些链接可以使您更了解Flutter-State-Management-Concept:

https://flutter.dev/docs/get-started/codelab

https://flutter.dev/docs/development/data-and-backend/state-mgmt/options