如何在Flutter中复刻Tinder式兴趣选择组件?
组件名称
这个组件是多选兴趣标签选择器,和Tinder的兴趣选择组件功能一致,核心是提供可点击切换选中状态的标签集合,并支持最低选择数量限制(你需求中的至少3个)。
Flutter实现方案
1. 核心状态管理
使用StatefulWidget维护选中标签集合与选择数量校验状态:
class InterestTagSelector extends StatefulWidget { final List<String> tags; final int minSelection; const InterestTagSelector({ super.key, required this.tags, this.minSelection = 3, }); @override State<InterestTagSelector> createState() => _InterestTagSelectorState(); } class _InterestTagSelectorState extends State<InterestTagSelector> { final Set<String> _selectedTags = {}; bool _hasEnoughSelection = false; @override void initState() { super.initState(); _checkSelectionCount(); } void _toggleTag(String tag) { setState(() { _selectedTags.contains(tag) ? _selectedTags.remove(tag) : _selectedTags.add(tag); _checkSelectionCount(); }); } void _checkSelectionCount() { setState(() => _hasEnoughSelection = _selectedTags.length >= widget.minSelection); }
2. 标签UI与交互实现
用Wrap实现流式布局,根据选中状态切换标签样式,同时添加数量校验提示:
@override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Wrap( spacing: 8.0, runSpacing: 8.0, children: widget.tags.map((tag) { final isSelected = _selectedTags.contains(tag); return GestureDetector( onTap: () => _toggleTag(tag), child: Container( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), decoration: BoxDecoration( color: isSelected ? Colors.pinkAccent : Colors.grey[200], borderRadius: BorderRadius.circular(20), ), child: Text( tag, style: TextStyle( color: isSelected ? Colors.white : Colors.black87, fontSize: 14, ), ), ), ); }).toList(), ), // 未达标提示 if (!_hasEnoughSelection) Padding( padding: const EdgeInsets.only(top: 12), child: Text( '请至少选择${widget.minSelection}个兴趣标签', style: TextStyle(color: Colors.red[400], fontSize: 12), ), ), // 确认按钮(按需添加) if (_hasEnoughSelection) Padding( padding: const EdgeInsets.only(top: 20), child: ElevatedButton( onPressed: () => print('选中标签:$_selectedTags'), style: ElevatedButton.styleFrom( backgroundColor: Colors.pinkAccent, fixedSize: const Size(double.infinity, 48), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)), ), child: const Text('确认', style: TextStyle(color: Colors.white)), ), ), ], ); } }
3. 组件调用示例
在页面中直接传入标签列表即可使用:
class InterestPage extends StatelessWidget { const InterestPage({super.key}); final List<String> _tags = const [ '音乐', '电影', '运动', '美食', '旅行', '读书', '摄影', '游戏', '健身', '绘画', '宠物', '科技' ]; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('选择兴趣')), body: Padding( padding: const EdgeInsets.all(16.0), child: InterestTagSelector(tags: _tags), ), ); } }
可选扩展功能
- 添加标签搜索过滤:结合
TextField实时筛选标签列表 - 自定义样式:支持传入自定义颜色、圆角、字体大小参数
- 选中动画:添加
AnimatedContainer实现选中时的过渡动画
内容的提问来源于stack exchange,提问作者EA19
相关产品推荐
相关产品推荐

