HarmonyOS 应用开发《掌上英语》第49篇:答题练习模式——两种答题 UI 的设计与实现

HarmonyOS 应用开发《掌上英语》第49篇:答题练习模式——两种答题 UI 的设计与实现 答题练习模式——两种答题 UI 的设计与实现一、两种答题模式的场景定位本项目中实现了两种答题页面分别适用于不同的练习场景页面文件名适用场景特点AnswerQuestionsPagefeatures/topicPage/…/AnswerQuestionsPage.ets日常练习单列模式、逐题作答AnswerQuestionsTwoPagefeatures/topicPage/…/AnswerQuestionsTwoPage.ets模考/测试双栏模式、倒计时、答题卡两种模式共享相同的数据源和答题逻辑但 UI 布局和交互体验各有特色。二、AnswerQuestionsPage——日常练习模式2.1 页面结构build(){AnswerQuestionsComponent({isCollectionEvent:(){this.isCollectionEvent();},confirmAddNote:(note:string){this.confirmAddNote(note);},storageWrongClick:(){this.storageWrongClick();},storageCollectClick:(){this.storageCollectClick();},viewReport:(){this.viewReport();},onClickBack:(){if(this.sourceRouterModel?.sourceType我的错题||...){RouterModule.pop();}else{this.backDialogController.open();}}});}AnswerQuestionsPage 本身是一个轻量壳将主要逻辑委托给AnswerQuestionsComponent位于 answer_questions 组件中。这种设计使得答题逻辑可以复用——无论是来自我的错题、“我的收藏还是日常练习”都使用同一套答题组件。2.2 数据初始化aboutToAppear():void{letnavParamRouterModule.getNavParam({url:RouterMap.ANSWER_QUESTIONS_PAGE});if(navParam!nullnavParam!undefined){if(navParaminstanceofQuestionsRouterModel){this.sourceRouterModelnavParamasQuestionsRouterModel;}else{letparamStrString(navParam);if(paramStr1){this.questionBankDataWORD_QUESTION_DATA;}elseif(paramStr2){this.questionBankDataLISTENING_QUESTION_DATA;}elseif(paramStr3){this.questionBankDataREADING_QUESTION_DATA;}elseif(paramStr5){this.questionBankDataGRAMMAR_QUESTION_DATA;}}}}路由参数支持两种传入方式QuestionsRouterModel带有完整题目列表的对象从错题本、收藏进入字符串标识1单词拼写、2听力、3阅读、5语法2.3 练习结束统计viewReport(){this.recordStudyData();lettestReport:TestReportModelnewTestReportModel();testReport.questhis.ques;testReport.quesType1;testReport.practiceDurationthis.practiceDuration;RouterModule.replace({url:RouterMap.ANSWER_REPORT_PAGE,param:testReport});}recordStudyData(){try{lettopicItemTypeListthis.toTopicItemTypeList(this.ques);StatisticsManager.getInstance().calculateStatistics(topicItemTypeList,this.practiceDuration);letplanManagerLearningPlanManager.getInstance();letansweredCountthis.ques.filter(itemitem.isAnswer).length;planManager.recordWordStudy(answeredCount);}catch(e){Logger.error(AnswerQuestionsPage,记录学习数据失败:${JSON.stringify(e)});}}练习完成后调用StatisticsManager.calculateStatistics计算统计数据同时更新学习计划。三、AnswerQuestionsTwoPage——模考模式3.1 页面结构AnswerQuestionsTwoPage 是一个完整的独立页面包含更多的模考专属功能build(){Column(){this.topBuilder();// 顶部导航this.countdownBuilder();// 倒计时this.answerPanelBuilder();// 作答面板this.bottomOperationBuilder();// 底部操作栏}.justifyContent(FlexAlign.SpaceBetween).backgroundColor($r(sys.color.comp_background_primary)).expandSafeArea([SafeAreaType.SYSTEM],[SafeAreaEdge.TOP,SafeAreaEdge.BOTTOM]);}3.2 倒计时功能BuildercountdownBuilder(){Row(){Image($r(app.media.ic_public_alarm_clock));Text($r(app.string.time_remaining));TextTimer({isCountDown:true,count:this.timerCount,controller:this.textTimerController}).format(HH:mm:ss).fontColor($r(sys.color.multi_color_09)).onTimer((_utc:number,elapsedTime:number){this.practiceDurationelapsedTime;}).onAppear((){this.textTimerController.start();});}}使用 ArkUI 的TextTimer组件实现 30 分钟倒计时isCountDown: true启用倒计时模式count: 30 * 60 * 1000设置 30 分钟毫秒format: HH:mm:ss显示格式onTimer回调中记录已用时间3.3 答题卡AnswerSheetBuilderanswerSheetBuilder(){Column(){Image($r(app.media.icon_answer_sheet));Text($r(app.string.answer_sheet));}.bindSheet($$this.isShowAnswerSheet,this.answerSheet(),{height:560,backgroundColor:$r(sys.color.background_secondary),showClose:false,}).onClick((){this.isShowAnswerSheettrue;});}答题卡通过bindSheet实现底部弹出面板用于快速跳转到任意题目。3.4 左右滑动切题.gesture(PanGesture(this.panOption).onActionUpdate((event:GestureEvent){if(event){this.offsetXthis.positionXevent.offsetX;}}).onActionEnd((){this.onActionEnd();}))onActionEnd(){if(this.offsetXthis.positionX){// 右滑 → 上一题this.currentIndex--;}else{// 左滑 → 下一题this.currentIndex;}this.currentModelthis.ques[this.currentIndex];this.positionXthis.offsetX;}使用PanGesture手势识别实现左右滑动切换题目PanDirection 设置为Left | Right。3.5 交卷功能nextQuestionBuilder(){Button(this.currentIndexthis.ques.length-1?$r(app.string.submit_exam):$r(app.string.next_question)).onClick((){if(this.currentIndexthis.ques.length-1){this.submitExamDialogController.open();}else{this.currentIndex;}});}最后一题时按钮文字变为交卷点击弹出确认对话框。四、两种模式的共同点4.1 单选逻辑answerEvent(item:AnswerItem){this.currentModel!.isAnswertrue;this.currentModel?.selectQues.splice(0);this.currentModel?.selectQues.push(item.ans);for(letindex0;indexthis.currentModel!.ques.length;index){letelementthis.currentModel!.ques[index];element.isSelect(element.ansitem.ans);}}单选逻辑清空已选、设置新选、标记选项状态。4.2 错题记录storageWrongClick(){if(this.currentModel.selectQues.toString()!this.currentModel.rightQues.toString()){letcurrentItemthis.transTopicItemType();letarr:TopicItemType[]PreferenceUtil.getInstance().get(PreferConstant.ERROR_RECORDS,[])asTopicItemType[];if(arr.length0){arr.push(currentItem);}else{letisExitarr.some(itemitem.keyIDcurrentItem.keyID);if(!isExit){arr.push(currentItem);}}PreferenceUtil.getInstance().put(PreferConstant.ERROR_RECORDS,arr);}}答错时自动将题目写入PreferConstant.ERROR_RECORDS存储。五、选择哪种模式比较维度AnswerQuestionsPageAnswerQuestionsTwoPage布局方式单列组件化双栏独立页面当前题目数量由数据源决定固定 30 分钟题目导航顺序作答答题卡 滑动时间限制无30 分钟倒计时生词本支持支持交卷方式手动报告弹框确认交卷前者适合日常碎片化学习后者适合模拟考试场景。两种模式的并存满足了用户学和测的不同需求。