当我回来或完成时如何重置我的控制器?

How do I reset my controller when I come back or finish?

我有一个 QuestionController class extends GetxController

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

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

_isAnswered = false;
_questionNumber.value = 1; 

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

有什么方法可以在页面退出时停止并重置?

控制器class代码:

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(),
            ],
          ),
        ],
      ),
    );
  }
}

您可以监听“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()
}

更新答案:

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

将此添加到您的控制器class。需要在 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 开始的索引

如果只有一个 controller.It 清除所有已注册的实例,则可以使用 Get.reset()。

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),
    ),
),

),

如果你只想重置一个控制器那么你可以使用Get.delete<ExecutableController>();

用于重置所有控制器Get.deleteAll();

Automatically:

 Get.to(() => DashboardPage(), binding: BindingsBuilder.put(() => DashboardController()));

Manually:

你可以在后面的 btn 上删除控制器,然后再把它放回去,它会给出与重置控制器相同的结果:

  1. 删除:

    Get.delete();

  2. 再次添加:

    Get.put(DashboardController());