如何在Flutter中实现类似Duolingo的选词组句功能?
实现Duolingo式单词拼接功能的优化方案
你当前用TextField实现的方案确实不够理想——输入框的编辑逻辑和Duolingo那种"点击单词填充到目标行、可随时移除调整"的交互不符,而且单词的复用、位置调整都会受限。这里给你一套更贴合需求的实现思路:
核心思路
- 用两个列表分别维护待选单词和已选单词的状态
- 目标句子区域用
Wrap组件展示已选单词,每个单词支持点击移除 - 待选单词区域用
Wrap展示可点击的单词按钮,点击后将单词移至已选列表
完整实现代码
import 'package:flutter/material.dart'; class Screen6_1_3 extends StatefulWidget { const Screen6_1_3({super.key}); @override State<Screen6_1_3> createState() => _Screen6_1_3State(); } class _Screen6_1_3State extends State<Screen6_1_3> { // 待选单词列表 final List<String> _availableWords = ["Bread", "I", "eat", "every", "morning"]; // 已选单词列表(用来组成目标句子) final List<String> _selectedWords = []; @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.blue, appBar: AppBar( centerTitle: true, backgroundColor: Colors.blue, leading: GestureDetector( child: const Icon(Icons.close, color: Colors.white), onTap: () { Navigator.pushNamedAndRemoveUntil(context, "home", (route) => false); }, ), ), body: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // 目标句子展示区域 Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 16), decoration: BoxDecoration( color: const Color.fromARGB(255, 226, 226, 226), border: Border.all(color: const Color.fromARGB(255, 123, 123, 123), width: 2), borderRadius: BorderRadius.circular(10), ), child: _selectedWords.isEmpty ? const Text("点击下方单词组成句子", style: TextStyle(color: Colors.grey)) : Wrap( spacing: 8, runSpacing: 8, children: _selectedWords.map((word) { return Chip( label: Text(word), onDeleted: () { // 点击移除按钮,将单词放回待选列表 setState(() { _selectedWords.remove(word); _availableWords.add(word); }); }, ); }).toList(), ), ), const SizedBox(height: 32), // 待选单词按钮区域 Wrap( spacing: 12, runSpacing: 12, children: _availableWords.map((word) { return ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Colors.white, foregroundColor: Colors.blue, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), ), onPressed: () { // 点击单词,移至已选列表 setState(() { _availableWords.remove(word); _selectedWords.add(word); }); }, child: Text(word), ); }).toList(), ), ], ), ), ); } }
方案优势
- 交互更贴合需求:完全模拟Duolingo的单词点击填充、移除调整逻辑,用户体验更直观
- 布局灵活:用
Wrap组件自动适配不同屏幕宽度,单词过多时会自动换行 - 状态管理清晰:两个列表分别维护待选和已选状态,后续扩展排序、错误校验、单词拖拽等功能都很方便
- 可扩展性强:可以轻松添加比如"重置句子"、"检查答案"等功能,只需操作两个列表即可
内容的提问来源于stack exchange,提问作者Igor Boldyrev
相关产品推荐
相关产品推荐

