Flutter实现无重复随机抽取4个名字的技术咨询
Flutter实现从名字列表中随机抽取4个不重复项
你当前的代码每次独立调用random.nextInt(names.length)随机取名字,导致重复概率很高。要实现无重复抽取,核心是每次抽取后排除已选中的项,同时处理名字数量不足的边界情况。
修改方案
替换原有的showAlertDialog方法,以下是完整修改后的代码:
import 'package:flutter/material.dart'; import 'dart:math'; class RandomName extends StatefulWidget { static const id = 'RandomName'; const RandomName({super.key}); @override State<RandomName> createState() => _RandomNameState(); } class _RandomNameState extends State<RandomName> { List<String> names = []; Random random = Random(); TextEditingController nameController = TextEditingController(); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.grey[900], appBar: AppBar(), body: Column( children: [ Expanded( child: ListView.builder( itemCount: names.length, itemBuilder: ((context, index) { return Dismissible( key: UniqueKey(), onDismissed: (direction) { setState(() { names.removeAt(index); }); }, child: ListTile( title: Text(names[index]), ), ); }))), Expanded( child: Padding( padding: EdgeInsets.all(20.0), child: Column( mainAxisAlignment: MainAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.stretch, children: <Widget>[ Text( "add new", style: TextStyle( color: Colors.grey.shade500, fontWeight: FontWeight.w600), ), Row( children: <Widget>[ Expanded( child: TextField( autocorrect: false, autofocus: true, maxLines: 1, cursorColor: Colors.grey.shade500, cursorWidth: 1.5, textInputAction: TextInputAction.done, keyboardAppearance: Brightness.dark, style: TextStyle( fontSize: 20, color: Colors.grey.shade500), textAlign: TextAlign.center, keyboardType: TextInputType.name, controller: nameController, decoration: const InputDecoration( border: InputBorder.none, contentPadding: EdgeInsets.only(top: 10, bottom: 10), isDense: true, ), ), ), ElevatedButton( child: Text('Add'), onPressed: () { addToList(); nameController.clear(); }, ) ], ), Builder( builder: (context) => ElevatedButton( child: Text('Get Random Name'), onPressed: () { showAlertDialog(context); })) ], ), ), ), ], ), ); } Future<void> showAlertDialog(BuildContext context) { return showDialog<void>( context: context, builder: (BuildContext context) { // 处理名字数量不足4个的情况 if (names.length < 4) { return AlertDialog( backgroundColor: Colors.grey.shade900, content: const Text( "至少需要添加4个名字才能抽取!", style: TextStyle(color: Colors.white), textAlign: TextAlign.center, ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text("确定"), ) ], ); } // 创建原列表的副本,避免修改原数据 List<String> tempNames = List.from(names); List<String> selectedNames = []; // 循环抽取4个不重复名字 for (int i = 0; i < 4; i++) { int randomIndex = random.nextInt(tempNames.length); selectedNames.add(tempNames[randomIndex]); tempNames.removeAt(randomIndex); // 移除已选中项,防止重复 } return AlertDialog( content: Container( margin: const EdgeInsets.all(8), padding: const EdgeInsets.all(5), width: MediaQuery.of(context).size.width / 1.3, height: MediaQuery.of(context).size.height / 3.5, color: Colors.grey.shade900, alignment: Alignment.center, child: Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: selectedNames.map((name) { return Text( name, textAlign: TextAlign.center, style: const TextStyle(fontSize: 15, color: Colors.white), ); }).toList(), ), ), backgroundColor: Colors.grey.shade900, ); }, ); } void addToList() { if (nameController.text.isNotEmpty) { setState(() { names.add(nameController.text); }); } } }
关键修改点
- 边界处理:先判断名字列表长度,不足4个时弹出提示,避免索引越界错误
- 无重复抽取:创建原列表的临时副本,每次抽取后移除已选中的名字,确保后续不会重复选中
- 代码优化:用
map方法动态生成展示名字的Text组件,替代重复的代码片段
内容的提问来源于stack exchange,提问作者JabiR Alzahrani
相关产品推荐
相关产品推荐

