【问题标题】:How do I reset my controller when I come back or finish?当我回来或完成时如何重置我的控制器?
【发布时间】:2025-12-30 21:25:11
【问题描述】:

我有一个 QuestionController 类扩展 GetxController

当我使用控件退出页面时,我希望它停止工作(因为它仍在后台运行)并在我回到该页面时重新开始。

我试过了:我在ScoreScreen()(在nextQuestion ())的路由之后添加了这些:

_isAnswered = false;
_questionNumber.value = 1; 

我在进入分数页面之前重置了值。如果您转到乐谱页面,它可能会起作用,但如果您早点回来,它就不会了。 (向上的问题 num/4 在这里不起作用)。所以这种方式不适合。

当页面退出时我可以停止并重置它的方式是什么?

控制器类代码:

class QuestionController extends GetxController
    with SingleGetTickerProviderMixin {
  PageController _pageController;

  PageController get pageController => this._pageController;

  List<Question> _questions = questions_data
      .map(
        (e) => Question(
            id: e["id"],
            question: e["question"],
            options: e["options"],
            answer: e["answer_index"]),
      )
      .toList();

  List<Question> get questions => this._questions;

  bool _isAnswered = false;

  bool get isAnswered => this._isAnswered;

  int _correctAns;

  int get correctAns => this._correctAns;

  int _selectedAns;

  int get selectedAns => this._selectedAns;

  RxInt _questionNumber = 1.obs;

  RxInt get questionNumber => this._questionNumber;

  int _numOfCorrectAns = 0;

  int get numOfCorrectAns => this._numOfCorrectAns;

  @override
  void onInit() {
    _pageController = PageController();
    super.onInit();
  }

  @override
  void onClose() {
    super.onClose();
    _pageController.dispose();
  }

  void checkAns(Question question, int selectedIndex) {
    _isAnswered = true;
    _correctAns = question.answer;
    _selectedAns = selectedIndex;

    if (_correctAns == _selectedAns) _numOfCorrectAns++;

    update();

    Future.delayed(Duration(seconds: 2), () {
      nextQuestion();
    });
  }

  void nextQuestion() {
    if (_questionNumber.value != _questions.length) {
      _isAnswered = false;
      _pageController.nextPage(
          duration: Duration(milliseconds: 300), curve: Curves.ease);
    } else {
      Get.off(ScoreScreen(correctNum: _numOfCorrectAns)); // GetMaterialApp()

      // _isAnswered = false;

      _numOfCorrectAns = 0;

      //_questionNumber.value = 1;

    }
  }

  void updateTheQuestionNum(int index) {
    _questionNumber.value = index + 1;
  }
}

完整代码如下

import 'package:flutter/material.dart';
import 'dart:async';
import 'package:get/get.dart';  // get: ^3.25.4

//  QuizPage()     ===============> 50. line      (Question 1/4) 81. line
//  QuestionCard()  ==============> 116. line
//  Option()   ===================> 163. line
//  QuestionController()  ========> 218. line
//  ScoreScreen() ================> 345. line

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(canvasColor: Colors.blue),
      home: HomeScreen(),
    );
  }
}

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Home Page"),
      ),
      body: Center(
        child: InkWell(
          onTap: () {
            Navigator.push(
                context, MaterialPageRoute(builder: (context) => QuizPage()));
          },
          child: Container(
            padding: EdgeInsets.all(22),
            color: Colors.green,
            child: Text(
              "Go Quiz Page",
              style: TextStyle(color: Colors.white),
            ),
          ),
        ),
      ),
    );
  }
}

class QuizPage extends StatelessWidget {
  const QuizPage({
    Key key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    QuestionController _questionController = Get.put(QuestionController());

    return Scaffold(
      appBar: AppBar(
        title: Text("Quiz Page"),
      ),
      body: Stack(
        children: [
          SafeArea(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                SizedBox(
                  height: 16,
                ),
                Padding(
                  padding: EdgeInsets.symmetric(horizontal: 16),
                  child: Obx(
                    () => Center(
                      child: RichText(
                          text: TextSpan(
                              // text,style default adjust here OR:children[TextSpan(1,adjust 1),TextSpan(2,adjust 2),..]
                              text:
                                  "Question ${_questionController._questionNumber.value}",
                              style: TextStyle(
                                  fontSize: 33, color: Colors.white70),
                              children: [
                            TextSpan(
                                text:
                                    "/${_questionController._questions.length}",
                                style: TextStyle(fontSize: 25))
                          ])),
                    ),
                  ),
                ),
                Divider(color: Colors.white70, thickness: 1),
                SizedBox(
                  height: 16,
                ),
                Expanded(
                  child: PageView.builder(
                    physics: NeverScrollableScrollPhysics(),
                    controller: _questionController._pageController,
                    onPageChanged: _questionController.updateTheQuestionNum,
                    itemCount: _questionController.questions.length,
                    itemBuilder: (context, index) => QuestionCard(
                      question: _questionController.questions[index],
                    ),
                  ),
                )
              ],
            ),
          )
        ],
      ),
    );
  }
}

class QuestionCard extends StatelessWidget {
  final Question question;

  const QuestionCard({
    Key key,
    @required this.question,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    QuestionController _controller = Get.put(QuestionController());

    return Container(
      margin: EdgeInsets.only(left: 16, right: 16, bottom: 16),
      padding: EdgeInsets.all(16),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(25),
        color: Colors.white,
      ),
      child: Column(
        children: [
          Text(
            question.question,
            style: TextStyle(fontSize: 22),
          ),
          SizedBox(
            height: 8,
          ),
          Flexible(
            child: SingleChildScrollView(
              child: Column(
                children: [
                  ...List.generate(
                      question.options.length,
                      (index) => Option(
                          text: question.options[index],
                          index: index,
                          press: () => _controller.checkAns(question, index)))
                ],
              ),
            ),
          )
        ],
      ),
    );
  }
}

class Option extends StatelessWidget {
  final String text;
  final int index;
  final VoidCallback press;

  const Option({
    Key key,
    @required this.text,
    @required this.index,
    @required this.press,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return GetBuilder<QuestionController>(
        init: QuestionController(),
        builder: (q) {
          Color getRightColor() {
            if (q.isAnswered) {
              if (index == q._correctAns) {
                return Colors.green;
              } else if (index == q.selectedAns &&
                  q.selectedAns != q.correctAns) {
                return Colors.red;
              }
            }
            return Colors.blue;
          }

          return InkWell(
            onTap: press,
            child: Container(
              //-- Option
              margin: EdgeInsets.only(top: 16),
              padding: EdgeInsets.all(16),
              decoration: BoxDecoration(
                  color: getRightColor(),
                  borderRadius: BorderRadius.circular(16)),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Text(
                    "${index + 1}. $text",
                    style: TextStyle(fontSize: 16, color: Colors.white),
                  ),
                ],
              ),
            ),
          );
        });
  }
}

class QuestionController extends GetxController
    with SingleGetTickerProviderMixin {
  PageController _pageController;

  PageController get pageController => this._pageController;

  List<Question> _questions = questions_data
      .map(
        (e) => Question(
            id: e["id"],
            question: e["question"],
            options: e["options"],
            answer: e["answer_index"]),
      )
      .toList();

  List<Question> get questions => this._questions;

  bool _isAnswered = false;

  bool get isAnswered => this._isAnswered;

  int _correctAns;

  int get correctAns => this._correctAns;

  int _selectedAns;

  int get selectedAns => this._selectedAns;

  RxInt _questionNumber = 1.obs;

  RxInt get questionNumber => this._questionNumber;

  int _numOfCorrectAns = 0;

  int get numOfCorrectAns => this._numOfCorrectAns;

  @override
  void onInit() {
    _pageController = PageController();
    //_pageController.addListener(() { _questionNumber.value = _pageController.page.round()+1; });
    super.onInit();
  }

  @override
  void onClose() {
    super.onClose();
    _pageController.dispose();
  }

  void checkAns(Question question, int selectedIndex) {
    _isAnswered = true;
    _correctAns = question.answer;
    _selectedAns = selectedIndex;

    if (_correctAns == _selectedAns) _numOfCorrectAns++;

    update();

    Future.delayed(Duration(seconds: 2), () {
      nextQuestion();
    });
  }

  void nextQuestion() {
    if (_questionNumber.value != _questions.length) {
      _isAnswered = false;
      _pageController.nextPage(
          duration: Duration(milliseconds: 300), curve: Curves.ease);
    } else {
      Get.off(ScoreScreen(correctNum: _numOfCorrectAns)); // GetMaterialApp()

      // _isAnswered = false;

      _numOfCorrectAns = 0;

      //_questionNumber.value = 1;

    }
  }

  void updateTheQuestionNum(int index) {
    _questionNumber.value = index + 1;
  }
}

class Question {
  final int id, answer;
  final String question;
  final List<String> options;

  Question({
    @required this.id,
    @required this.question,
    @required this.options,
    @required this.answer,
  });
}

const List questions_data = [
  {
    "id": 1,
    "question": "Question 1",
    "options": ['option A', 'B', 'C', 'D'],
    "answer_index": 3,
  },
  {
    "id": 2,
    "question": "Question 2",
    "options": ['option A', 'B', 'C', 'D'],
    "answer_index": 2,
  },
  {
    "id": 3,
    "question": "Question 3",
    "options": ['option A', 'B', 'C', 'D'],
    "answer_index": 0,
  },
  {
    "id": 4,
    "question": "Question 4",
    "options": ['option A', 'B', 'C', 'D'],
    "answer_index": 0,
  },
];

class ScoreScreen extends StatelessWidget {
  final int correctNum;

  ScoreScreen({@required this.correctNum});

  @override
  Widget build(BuildContext context) {
    QuestionController _qController = Get.put(QuestionController());

    return Scaffold(
      body: Stack(
        fit: StackFit.expand,
        children: [
          Column(
            children: [
              Spacer(
                flex: 2,
              ),
              Text(
                "Score",
                style: TextStyle(fontSize: 55, color: Colors.white),
              ),
              Spacer(),
              Text(
                "${correctNum * 10}/${_qController.questions.length * 10}",
                style: TextStyle(fontSize: 33, color: Colors.white),
              ),
              Spacer(
                flex: 2,
              ),
              InkWell(
                onTap: () => Get.back(),
                borderRadius: BorderRadius.circular(16),
                child: Container(
                  padding: EdgeInsets.all(16),
                  decoration: BoxDecoration(
                      borderRadius: BorderRadius.circular(16),
                      color: Colors.white24),
                  child: Text(
                    "Back to Home Page",
                    style: TextStyle(color: Colors.white),
                  ),
                ),
              ),
              Spacer(),
            ],
          ),
        ],
      ),
    );
  }
}

【问题讨论】:

  • QuestionController 类的哪个部分负责显示 Question 1/4 部分的显示?
  • _q._questionNumber.value (1) 和 _q._questions.length (4)

标签: flutter dart flutter-getx


【解决方案1】:

更新答案:

好的,在看到您的完整代码后,我的解决方案需要几个额外的步骤。

将此添加到您的控制器类。它需要在您的HomeScreen 的 onPressed 中调用

 void resetQuestionNumber() => _questionNumber.value = 1;

您必须提前初始化控制器,以便将其添加到您的 HomeScreen

final _questionController = Get.put(QuestionController());

HomeScreenonTap 现在看起来像这样。

onTap: () {
    _questionController.resetQuestionNumber();
    Navigator.push(
    context, MaterialPageRoute(builder: (context) => QuizPage()));
},

应该这样做。 _pageController 索引直到您回答问题后才更新,因此只需要在转到 QuizPage 之前重置 _questionNumber ,然后它就会赶上。您的updateTheQuestionNum 可以完全消失,您不再需要在PageView.builderonPageChanged 中处理任何此类问题。

原答案:

如果您只希望 RxInt _questionNumber_pageController 的值匹配,您可以在 onInit 中添加一个侦听器

_pageController.addListener(() {
  _questionNumber.value = _pageController.page.round() + 1;
});

编辑:添加 + 1 以说明从 0 开始的索引

【讨论】:

  • 我仍然得到相同的显示。 (例如;关于 1. 问题。但出现“问题 3/4”)
  • 如果你分享你的 UI 代码,我可以看看。但一般来说,假设 _pageController 是控制我们在您的帖子中看到的页面的东西,那么在您的 UI 中,Obx(()=&gt;Text(controller.questionNumber.value.toString()) 将遵循 _pagecontroller 索引并在您切换页面时更新。
  • 另外,根据我的建议,您不需要updateTheQuestionNum,因为除了_pageController 索引之外,您不希望有任何其他更改_questionNumber 的值。
  • 我添加了完整的代码。也许我错过了什么。
  • 我看到发生了什么,看到更新的答案。现在可以了。确保在测试之前取消注释 onInit 中的 addListener 部分。
【解决方案2】:

您可以收听“onBack 事件”并处置控制器 这是一个例子

@override
Widget build(BuildContext context) {
  return WillPopScope(
    onWillPop: () {
      disposeController(context);
    },
    child: Scaffold(
      key: _scaffoldKey,
      appBar: AppBar(
        leading: IconButton(
            icon: Icon(Icons.arrow_back),
            onPressed: () {
              _moveToSignInScreen(context);
            }),
        title: Text("Profile"),
      ),
    ),
  );

}

void disposeController(BuildContext context){
//or what you wnat to dispose/clear
 _pageController.dispose()
}

【讨论】:

  • @zeed 你解决了这个问题 PageController 在被处理后被使用了。
【解决方案3】:

如果您只有一个控制器,您可以使用 Get.reset()。它会清除所有已注册的实例。

【讨论】:

    【解决方案4】:
    InkWell(
    onTap: () {
        /*add QuestionController().refresh();*/
        QuestionController().refresh();
        Get.back();
    },
    borderRadius: BorderRadius.circular(16),
    child: Container(
    padding: EdgeInsets.all(16),
    decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(16),
        color: Colors.white24),
    ),
    child: Text(
        Back to Home Page",
        style: TextStyle(color: Colors.white),
        ),
    ),
    

    ),

    【讨论】:

    • 正如目前所写,您的答案尚不清楚。请edit 添加其他详细信息,以帮助其他人了解这如何解决所提出的问题。你可以找到更多关于如何写好答案的信息in the help center
    最近更新 更多