如何在SingleChildScrollView中管理自定义卡片的选中状态
实现卡片单选选中效果的解决方案
以下是针对需求修改后的代码,实现点击卡片切换样式(背景色、边框色)、添加底部绿色匹配宽度方块,且保持单选状态:
修改后的CategoryCard组件
import 'package:flutter/material.dart'; class CategoryCard extends StatelessWidget { final String? categoryCardName; final Function()? wasPressed; final bool isSelected; // 标记当前卡片是否选中 const CategoryCard({ super.key, required this.categoryCardName, this.wasPressed, required this.isSelected, }); @override Widget build(BuildContext context) { return GestureDetector( onTap: wasPressed, child: Card( elevation: isSelected ? 2 : 0, // 选中时添加轻微阴影增强视觉效果 shape: RoundedRectangleBorder( side: BorderSide( color: isSelected ? Colors.green : const Color.fromRGBO(212, 213, 215, 1), width: 3, ), borderRadius: BorderRadius.circular(20.0), ), child: Column( mainAxisSize: MainAxisSize.min, children: [ Container( decoration: BoxDecoration( color: isSelected ? Colors.green.shade50 : const Color.fromRGBO(242, 243, 243, 1), borderRadius: const BorderRadius.vertical(top: Radius.circular(20.0)), ), padding: const EdgeInsets.all(10), child: Text( categoryCardName ?? 'Todas', style: TextStyle( fontSize: 25, fontWeight: FontWeight.bold, color: isSelected ? Colors.green : const Color.fromRGBO(91, 94, 99, 1), ), ), ), // 选中时显示底部绿色方块,宽度匹配卡片 if (isSelected) Container( height: 4, width: double.infinity, decoration: const BoxDecoration( color: Colors.green, borderRadius: BorderRadius.vertical(bottom: Radius.circular(20.0)), ), ), ], ), ), ); } }
修改后的MyHomePage页面
import 'package:flutter/material.dart'; import 'category_card.dart'; import 'category_card_model.dart'; class MyHomePage extends StatefulWidget { MyHomePage({super.key, required this.title}); final String title; @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { final categoryCardModelList = <CategoryCardModel>[ CategoryCardModel("Todas"), CategoryCardModel("Smartphones"), CategoryCardModel("Accesorios para celular"), CategoryCardModel("TV") ]; List<CategoryCardModel>? _categoryCardModelListOf; CategoryCardModel? _selectedCategory; // 跟踪当前选中的卡片 @override void initState() { super.initState(); _categoryCardModelListOf = List.of(categoryCardModelList); // 可选:默认选中第一个卡片 _selectedCategory = _categoryCardModelListOf?.first; } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: SingleChildScrollView( scrollDirection: Axis.horizontal, padding: const EdgeInsets.fromLTRB(10.0, 0.0, 10.0, 0.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: _categoryCardModelListOf! .map<Widget>((categoryCardModel) => CategoryCard( wasPressed: () { setState(() { _selectedCategory = categoryCardModel; // 更新选中状态 }); }, categoryCardName: categoryCardModel.categoryCardModelName, isSelected: _selectedCategory == categoryCardModel, // 传递选中状态 )) .toList(), ), ), ); } }
关键改动说明
- 选中状态跟踪:在页面状态类中新增
_selectedCategory变量,用于记录当前选中的卡片模型,确保单选逻辑。 - 动态样式控制:给
CategoryCard添加isSelected参数,根据该参数切换边框色、背景色、文字颜色,选中时使用绿色系样式。 - 底部绿色方块:将卡片内部布局改为
Column,在底部添加绿色容器,仅在选中时显示,宽度设为double.infinity以匹配卡片宽度,圆角与卡片保持一致。 - 单选逻辑实现:点击卡片时通过
setState更新_selectedCategory,触发UI刷新,保证同一时间只有一个卡片处于选中状态。
内容的提问来源于stack exchange,提问作者MATEO VALENCIA MINOTA
相关产品推荐
相关产品推荐

