一、预览
预览
二、使用
1. 获取试题
(1) 实体
class ExamQuestions {
int? id;
int? level;
String? subject;
String? title;
int? right;
String? a;
String? b;
String? c;
String? d;
int? addtime;
int? deltime;
}
(2) 使用
var myExamQuestions = [ExamQuestions()];
/// 获取笔试题目列表
getUserExamQuestions() async {
var allQuestions = /// 获取试题接口
setState(() {
myExamQuestions = allQuestions;
});
}
2. 倒计时
late Timer _timer;
var showTime = "20分";
/// 格式化时间
renderTime(int value) {
if (value == 0) {
return "0秒";
}
var min = value ~/ 60;
var second = value % 60;
if(min == 0){
return "$second秒";
}
return "$min分$second秒";
}
/// 倒计时
void startCountdownTimer() {
var countdownTime = 1200;
const oneSec = const Duration(seconds: 1);
var callback = (timer) async {
if (countdownTime == 0) {
_timer.cancel();
toastShow("已超时,自动提交笔试考试");
} else {
setState(() {
countdownTime = countdownTime - 1;
showTime = renderTime(countdownTime);
});
}
};
_timer = Timer.periodic(oneSec, callback);
}
3. 检测题目及放弃考试
检测完成的题目
/// 检测完成的题目
testCompleteQuestion(){
var temp = 0;
selectOptions.forEach((element) {
if(element != 0){
temp++;
}
});
setState(() {
completeQuestion = temp;
});
}
放弃考试
/// 放弃考试
_giveUpTheTest(context){
return
showDialog<Null>(
context: context,
builder: (BuildContext context) {
return SimpleDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.dp),
),
children: <Widget>[
Get.getWidthBox(MediaQuery.of(context).size.width),
Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Get.getHeightBox(20.dp),
singleTextWeight("请在放弃考试前确认", c_00, 18.dp, fontWeight: FontWeight.bold),
Get.getHeightBox(40.dp),
Container(
width: MediaQuery.of(context).size.width,
child: Column(
children: [
Container(
height: 0.5.dp,
color: c_FF,
width: MediaQuery.of(context).size.width,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
GestureDetector(
onTap: ()=> Navigator.of(context).pop(),
child: singleTextWeight("继续考试", c_00, 18.dp, fontWeight: FontWeight.normal)
),
Container(
height: 99.5.dp,
color: c_FF,
width: 0.5.dp,
),
GestureDetector(
onTap: ()=>Get.close(2),
child: singleTextWeight("确认", c_00, 18.dp, fontWeight: FontWeight.normal)
),
],
)
],
),
)
],
)
],
);
},
);
}
4. 总览
import 'dart:async';
/// 第三方
import 'package:get/get.dart';
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
/// 本地资源
import '../../../data/api/subject.dart';
import '../../../data/model/subject.dart';
import '../../../theme/utils/export.dart';
import '../../../utils/widget/common.dart';
class TestPage extends StatefulWidget {
@override
_TestPageState createState() => _TestPageState();
}
class _TestPageState extends State<TestPage> {
var myExamQuestions = [ExamQuestions()];
PageController _pageController = PageController(initialPage: 0);
var selectOptions = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0].obs;
var nowPageSelect = 0;
late Timer _timer;
var showTime = "20分";
/// 已完成的题目
var completeQuestion = 0;
/// 按钮名称
var tableInfo = "下一题";
/// 当前页
var page = 0;
/// 获取笔试题目列表
getUserExamQuestions() async {
var allQuestions = await SubjectAPI.getExamQuestionList(8, 10, "少儿歌唱");
setState(() {
myExamQuestions = allQuestions;
});
}
/// 格式化时间
renderTime(int value) {
if (value == 0) {
return "0秒";
}
var min = value ~/ 60;
var second = value % 60;
if(min == 0){
return "$second秒";
}
return "$min分$second秒";
}
/// 倒计时
void startCountdownTimer() {
var countdownTime = 1200;
const oneSec = const Duration(seconds: 1);
var callback = (timer) async {
if (countdownTime == 0) {
_timer.cancel();
/// toast信息
Fluttertoast.showToast(
msg: "已超时,自动提交笔试考试",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.CENTER,
timeInSecForIosWeb: 1,
fontSize: 16.0
);
} else {
setState(() {
countdownTime = countdownTime - 1;
showTime = renderTime(countdownTime);
});
}
};
_timer = Timer.periodic(oneSec, callback);
}
/// 检测完成的题目
testCompleteQuestion(){
var temp = 0;
selectOptions.forEach((element) {
if(element != 0){
temp++;
}
});
setState(() {
completeQuestion = temp;
});
}
@override
void initState(){
getUserExamQuestions();
startCountdownTimer();
super.initState();
}
@override
void dispose(){
_timer.cancel();
super.dispose();
}
/// 放弃考试
_giveUpTheTest(context){
return
showDialog<Null>(
context: context,
builder: (BuildContext context) {
return SimpleDialog(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.dp),
),
children: <Widget>[
Get.getWidthBox(MediaQuery.of(context).size.width),
Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Get.getHeightBox(20.dp),
singleTextWeight("请在放弃考试前确认", c_00, 18.dp, fontWeight: FontWeight.bold),
Get.getHeightBox(40.dp),
Container(
width: MediaQuery.of(context).size.width,
child: Column(
children: [
Container(
height: 0.5.dp,
color: c_FF,
width: MediaQuery.of(context).size.width,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
GestureDetector(
onTap: ()=> Navigator.of(context).pop(),
child: singleTextWeight("继续考试", c_00, 18.dp, fontWeight: FontWeight.normal)
),
Container(
height: 99.5.dp,
color: c_FF,
width: 0.5.dp,
),
GestureDetector(
onTap: ()=>Get.close(2),
child: singleTextWeight("确认", c_00, 18.dp, fontWeight: FontWeight.normal)
),
],
)
],
),
)
],
)
],
);
},
);
}
Widget body1(position){
return Padding(
padding: EdgeInsets.only(left: 26.dp, top: 20.dp, right: 26.dp, bottom: 20.dp),
child: Container(
decoration: BoxDecoration(
color: c_FF,
borderRadius: BorderRadius.all(
Radius.circular(20.dp),
),
),
child: Padding(
padding: EdgeInsets.only(top: 16.dp),
child: Column(
children: [
singleTextWeight("${position + 1}. ${myExamQuestions[position].title}", c_00, 18.dp, fontWeight: FontWeight.bold, overflow: TextOverflow.clip),
Get.getHeightBox(10.dp),
customerContainer(60.dp, MediaQuery.of(context).size.width, c_FF, 20.dp,
body: Row(
children: [
Image.asset(
selectOptions[position] == 1 ? R.imagesCommonRadiusSelectIcon : R.imagesCommonRadiusNoSelectIcon,
width: 18.dp,
height: 18.dp,
),
Get.getWidthBox(10.dp),
Expanded(child: singleTextWeight("A ${myExamQuestions[position].a}", c_00, 16.dp, overflow: TextOverflow.clip))
],
),
onTap: ()=>{
selectOptions[position] = 1,
testCompleteQuestion()
},
margin: EdgeInsets.only(top: 10.dp, bottom: 10.dp)
),
customerContainer(60.dp, MediaQuery.of(context).size.width, c_FF, 20.dp,
body: Row(
children: [
Image.asset(
selectOptions[position] == 2 ? R.imagesCommonRadiusSelectIcon : R.imagesCommonRadiusNoSelectIcon,
width: 18.dp,
height: 18.dp,
),
Get.getWidthBox(10.dp),
Expanded(child: singleTextWeight("B ${myExamQuestions[position].b}", c_00, 16.dp, overflow: TextOverflow.clip))
],
),
onTap: ()=>{
selectOptions[position] = 2,
testCompleteQuestion()
},
margin: EdgeInsets.only(top: 10.dp, bottom: 10.dp)
),
customerContainer(60.dp, MediaQuery.of(context).size.width, c_FF, 20.dp,
body: Row(
children: [
Image.asset(
selectOptions[position] == 3 ? R.imagesCommonRadiusSelectIcon : R.imagesCommonRadiusNoSelectIcon,
width: 18.dp,
height: 18.dp,
),
Get.getWidthBox(10.dp),
Expanded(child: singleTextWeight("C ${myExamQuestions[position].c}", c_00, 16.dp, overflow: TextOverflow.clip))
],
),
onTap: ()=>{
selectOptions[position] = 3,
testCompleteQuestion()
},
margin: EdgeInsets.only(top: 10.dp, bottom: 10.dp)
),
customerContainer(60.dp, MediaQuery.of(context).size.width, c_FF, 20.dp,
body: Row(
children: [
Image.asset(
selectOptions[position] == 4 ? R.imagesCommonRadiusSelectIcon : R.imagesCommonRadiusNoSelectIcon,
width: 18.dp,
height: 18.dp,
),
Get.getWidthBox(10.dp),
Expanded(child: singleTextWeight("D ${myExamQuestions[position].d}", c_00, 16.dp, overflow: TextOverflow.clip))
],
),
onTap: ()=>{
selectOptions[position] = 4,
testCompleteQuestion()
},
margin: EdgeInsets.only(top: 10.dp, bottom: 10.dp)
),
],
),
),
),
);
}
/// 主内容
Widget mainBody(BuildContext context){
return Column(
children: [
safePadding(context, c_FF),
customerHeader(context, c_FF, "笔试考试", leftContent: GestureDetector(
onTap: ()=>_giveUpTheTest(context),
child: Image.asset(
R.imagesCommonBackIcon,
width: 24.dp,
height: 24.dp,
),
)),
Expanded(
child: (myExamQuestions.length > 0 && myExamQuestions[0].title != null) ? PageView.builder(
controller: _pageController,
physics: NeverScrollableScrollPhysics(),
itemBuilder: (context, position) => body1(position),
itemCount: myExamQuestions.length,
onPageChanged: (index){
},
) : Text(""),
),
Padding(
padding: EdgeInsets.only(left: 26.dp, top: 10.dp, right: 26.dp, bottom: 10.dp),
child: Container(
decoration: BoxDecoration(
color: c_FF,
borderRadius: BorderRadius.all(
Radius.circular(20.dp),
),
),
child: Padding(
padding: EdgeInsets.only(top: 16.dp),
child: Row(
children: [
singleTextWeight("倒计时:$showTime", c_FDAE2D, 16.dp),
Expanded(child: Text("")),
singleTextWeight("完成度:$completeQuestion/${myExamQuestions.length}道题", c_FDAE2D, 16.dp)
],
),
),
),
),
customerContainer(46.dp, MediaQuery.of(context).size.width, c_FDAE2D, 10.dp, body: Center(
child: singleTextWeight("$tableInfo", c_FF, 16.dp),
), margin: EdgeInsets.only(bottom: 16.dp, left: 16.dp, right: 16.dp, top: 16.dp),
onTap: (){
setState(() {
page ++;
});
if(page == myExamQuestions.length - 1){
setState((){
tableInfo = "提交成绩";
});
}
_pageController.jumpToPage(page);
}
)
],
);
}
@override
Widget build(BuildContext context) {
return customerTheme(false, SystemUiOverlayStyle.dark, mainBody(context), boxDecoration: BoxDecoration(
color: c_FC
), willPop: true);
}
}