导航到测验应用程序中的下一个问题或项目



我正在创建一个dart/flutter测验应用程序,我想在选择答案时自动导航到下一个问题。问题和答案在一个列表中。请有人指出我哪里做错了。这是我的代码

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../providers/quiz/question_provider.dart';
import '../providers/quiz/quiz_provider.dart';
import '../widgets/quiz/question_item.dart';

class QuestionScreen extends StatefulWidget {
static var quizId;
static const routeName = '/question-screen';
@override
State<QuestionScreen> createState() => _QuestionScreenState();
}
class _QuestionScreenState extends State<QuestionScreen> {
var _isInit = true;
var _isLoading = false;
@override
void didChangeDependencies() {
if (_isInit) {
setState(() {
_isLoading = true;
});
Provider.of<Question>(context).fetchQuestions().then((_) {
setState(() {
_isLoading = false;
});
});
}
_isInit = false;
super.didChangeDependencies();
}
// var _questionIndex = 0;
// void answerQuestion() {
//   setState(() {
//     _questionIndex = _questionIndex + 1;
//   });
// }
@override
Widget build(BuildContext context) {
QuestionScreen.quizId = ModalRoute.of(context)!.settings.arguments as String;
final quiz = Provider.of<Quiz>(context).findById(QuestionScreen.quizId);
final question = Provider.of<Question>(context);

return Scaffold(
appBar: AppBar(
title: Text('${quiz.title}'),
),
body: Container(
padding: EdgeInsets.all(10),
child: ListView.builder(
itemCount: 1,
itemBuilder: (ctx, index) => ChangeNotifierProvider.value(
value: question.questions[index],
child: question.questions.isEmpty ? Container() : QuestionItem(),
),
),
),
);
}
}
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '/providers/quiz/question_provider.dart';
import '/screens/question_answers.dart';
import './question.dart';
import './answer.dart';
class QuestionItem extends StatefulWidget {
final Function? answerHandler;
const QuestionItem({Key? key, this.answerHandler}) : super(key: key);
@override
State<QuestionItem> createState() => _QuestionItemState();
}
class _QuestionItemState extends State<QuestionItem> {
@override
Widget build(BuildContext context) {
final loadedQuestions = Provider.of<Question>(context);
var questionIndex = 1;

void answerQuestion() {
setState(() {
questionIndex = questionIndex! + 1;
});
}
return GridTile(
child: GestureDetector(
onTap: () =>
Navigator.of(context).pushNamed(QuestionsAndAnswers.routeName),
child: Column(
children: [
QuestionText(
questionText: '${loadedQuestions.questionTitle!}'),
...(loadedQuestions.options as List<dynamic>).map((option) {
return Answer(
answerText: '${option}',
selectHandler: answerQuestion,
);
}).toList()
],
),
),
);
}
}

下面是提供程序类,我从API中获取测验数据并将它们添加到列表中。

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:firebase_auth/firebase_auth.dart';
import '/screens/question_screen.dart';
class Question with ChangeNotifier {
final String? id;
final String? questionTitle;
final String? description;
final String? lessonId;
final String? courseId;
final String? quizId;
final String? media;
final List<dynamic>? rightAnswers;
final List<dynamic>? options;
final int? grade = 1;
int? index = 0;
Question({
@required this.id,
@required this.questionTitle,
@required this.description,
@required this.lessonId,
@required this.courseId,
@required this.quizId,
@required this.media,
@required this.rightAnswers,
@required this.options,
@required this.index,
});
List<Question> _questions = [];
List<Question> get questions {
return [..._questions];
}
Question findById(String id) {
return _questions.firstWhere((question) => question.id == id);
}
Future<void> fetchQuestions() async {
try {
final String idToken =
await FirebaseAuth.instance.currentUser!.getIdToken();
final reauthUrl = Uri.parse(
'https://example.net/api/v1/User/reauth');
final reauthResponse = await http.post(reauthUrl,
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: json.encode({"token": idToken}));
final returnedTokenData =
json.decode(reauthResponse.body) as Map<String, dynamic>;
final serverToken = returnedTokenData['token'];
final url = Uri.parse(
'https://example.net/api/v1/Quiz/Questions/${QuestionScreen.quizId}');
final response = await http.get(
url,
headers: {'Authorization': 'Bearer $serverToken'},
);
final responseData = json.decode(response.body);
print('ResponseData is $responseData');
final List<Question> loadedQuestions = [];
for (var question in responseData) {
loadedQuestions.add(
Question(
id: question['id'],
questionTitle: question['title'], 
description: question['description'],
lessonId: question['lessonId'],
courseId: question['courseId'],
quizId: question['quizId'],
media: question['media'],
rightAnswers: question['rightAnswers'],
options: question['options'],
),
);
}
_questions = loadedQuestions;
print('These are the questions $_questions');
notifyListeners();
} catch (error) {
rethrow;
}
}
}

我终于想到了一个导航到测试中下一个问题的方法。

我将questionIndex变量和answerQuestion()函数从QuestionItem类移动到QuestionScreen页面,并将该函数作为参数传递到QuestionItem小部件中。

然后我用question.questions[questionIndex]作为ListView.builder()value,瞧!它的工作原理!

这是最后的代码

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../providers/quiz/question_provider.dart';
import '../providers/quiz/quiz_provider.dart';
import '../widgets/quiz/question_item.dart';

class QuestionScreen extends StatefulWidget {
static var quizId;
static const routeName = '/question-screen';
@override
State<QuestionScreen> createState() => _QuestionScreenState();
}
class _QuestionScreenState extends State<QuestionScreen> {
var _isInit = true;
var _isLoading = false;
var questionIndex = 0;
@override
void didChangeDependencies() {
if (_isInit) {
setState(() {
_isLoading = true;
});
Provider.of<Question>(context).fetchQuestions().then((_) {
setState(() {
_isLoading = false;
});
});
}
_isInit = false;
super.didChangeDependencies();
}
void answerQuestion() {
setState(() {
questionIndex = questionIndex + 1;
});
}
@override
Widget build(BuildContext context) {
QuestionScreen.quizId = ModalRoute.of(context)!.settings.arguments as String;
final quiz = Provider.of<Quiz>(context).findById(QuestionScreen.quizId);
final question = Provider.of<Question>(context);

return Scaffold(
appBar: AppBar(
title: Text('${quiz.title}'),
),
body: Container(
padding: EdgeInsets.all(10),
child: ListView.builder(
itemCount: 1,
itemBuilder: (ctx, index) => ChangeNotifierProvider.value(
value: question.questions[questionIndex],
child: question.questions.isEmpty ? Container() : QuestionItem(answerHandler: answerQuestion),
),
),
),
);
}
}
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '/providers/quiz/question_provider.dart';
import '/screens/question_answers.dart';
import './question.dart';
import './answer.dart';
class QuestionItem extends StatefulWidget {
final VoidCallback answerHandler;
const QuestionItem({Key? key, required this.answerHandler}) : super(key: key);
@override
State<QuestionItem> createState() => _QuestionItemState();
}
class _QuestionItemState extends State<QuestionItem> {
@override
Widget build(BuildContext context) {
final loadedQuestions = Provider.of<Question>(context);
return GridTile(
child: GestureDetector(
onTap: () =>
Navigator.of(context).pushNamed(QuestionsAndAnswers.routeName),
child: Column(
children: [
QuestionText(questionText: '${loadedQuestions.questionTitle!}'),
SizedBox(height: 10,),
...(loadedQuestions.options as List<dynamic>).map((option) {
return Answer(
answerText: '${option}',
selectHandler: widget.answerHandler,
);
}).toList(),
],
),
),
);
}
}

相关内容

最新更新