如何在Flutter中实现多个RadioListTile满足单选题独立选中需求
问题原因
RadioListTile的value和groupValue类型不匹配:你给value传的是选项字符串(solucion1/2/3),但groupValue用的是int类型的selectedvalue[index],二者永远无法匹配,导致单选分组逻辑完全失效,出现多题同步选中的异常。- 选中值存储没有按题目隔离:你用全局的
option1/option2/option3三个变量存储所有题的选择,不同题的选择会互相覆盖,无法保存每道题的独立选择结果。 - 初始化逻辑位置错误:你把选中值数组的初始化放在了
itemBuilder中,每次渲染列表项都会重复执行判断,存在性能问题。
修复后的完整代码
class _QuizViewer extends State<QuizViewer> { // 存储每道题的选中结果,索引对应题目顺序,null代表未选择 List<String?> selectedValue = []; @override void initState() { super.initState(); } @override Widget build(BuildContext context) { return FutureBuilder<List<Quizzes>>( future: fetchQuizzes(widget.quizid), builder: (context, snapshot) { if (snapshot.hasError) { return Scaffold( appBar: AppBar( title: const Text('No hay quizzes publicados'), backgroundColor: Colors.green[700], ), backgroundColor: Colors.grey[100], ); } else if (snapshot.hasData) { final quizList = snapshot.data!; // 拿到题目数据后初始化选中数组,只执行一次 if (selectedValue.isEmpty) { selectedValue = List.filled(quizList.length, null); } return Scaffold( appBar: AppBar( title: const Text('Quizzes disponibles'), backgroundColor: Colors.green[700], ), body: ListView.builder( itemCount: quizList.length, itemBuilder: (BuildContext context, int index) { final currentQuiz = quizList[index]; return Container( padding: const EdgeInsets.symmetric(horizontal: 16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 20), Text(currentQuiz.question), const SizedBox(height: 10), RadioListTile<String>( value: currentQuiz.solucion1, title: Text(currentQuiz.solucion1), onChanged: (val) => setState(() { // 只修改当前题目的选中值 selectedValue[index] = val; }), groupValue: selectedValue[index], ), const SizedBox(height: 10), RadioListTile<String>( value: currentQuiz.solucion2, title: Text(currentQuiz.solucion2), onChanged: (val) => setState(() { selectedValue[index] = val; }), groupValue: selectedValue[index], ), const SizedBox(height: 10), RadioListTile<String>( value: currentQuiz.solucion3, title: Text(currentQuiz.solucion3), onChanged: (val) => setState(() { selectedValue[index] = val; }), groupValue: selectedValue[index], ), ], ), ); }, ), floatingActionButton: FloatingActionButton.extended( onPressed: () { // 直接过滤未作答的题目,得到结果数组 final submitResult = selectedValue.where((e) => e != null).toList(); print(submitResult); // 这里直接把submitResult传给服务端即可 }, label: const Text('Mis entregas')), ); } else { return Scaffold( appBar: AppBar( title: const Text('No hay quizzes publicados'), backgroundColor: Colors.green[700], ), backgroundColor: Colors.grey[100], ); } }, ); } }
核心修改说明
- 把存储选中值的数组改为
List<String?>类型,每个索引对应一道题的选择结果,天然实现不同题目选择的隔离。 - 选中数组的初始化移到接口拿到题目数据之后执行,避免重复渲染时的冗余逻辑。
- 给
RadioListTile指定泛型String,保证value和groupValue类型匹配,单选分组逻辑恢复正常,每道题的选择互不影响。 - 提交时直接从
selectedValue数组中过滤掉未作答的空值,即可得到符合要求的结果数组,不需要额外组装。
内容的提问来源于stack exchange,提问作者Irwin
相关产品推荐
相关产品推荐

