Flutter GridView按钮单选切换颜色实现方法问询
输出界面
This is the output screen
需求与问题
现有基于Flutter实现的GridView兴趣选择界面,需实现以下单选交互:
- 点击任意按钮时,该按钮变为金色样式,其余按钮保持原有状态
- 再次点击已选中的按钮,恢复其正常颜色,取消选择
- 全程仅支持单选一个按钮
实现方案
核心思路
- 定义状态变量存储当前选中的兴趣项标识(ID或索引)
- 点击按钮时更新选中状态:已选中则取消,未选中则切换为当前项
- 根据选中状态动态渲染按钮的样式(背景/边框颜色等)
修改后的完整代码片段
// 在State类中添加选中状态变量 String? selectedInterestId; return Scaffold( body: SafeArea( child: SingleChildScrollView( physics: const BouncingScrollPhysics(), child: Column( children: [ Container( height: MediaQuery.of(context).size.height, width: MediaQuery.of(context).size.width, decoration: BoxDecoration( image: const DecorationImage( image: AssetImage('assets/images/frame.png'), fit: BoxFit.fill), color: AppColors.purewhite), child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ GestureDetector( onTap: () { Get.to(GenderScreen()); }, child: Padding( padding: const EdgeInsets.all(15.0), child: Icon(Icons.arrow_back_ios_new, color: AppColors.textgreen), ), ), Column(children: [ const Padding( padding: EdgeInsets.symmetric(vertical: 20), child: CustomIcon( svgIcon: 'assets/images/fourstep.svg', size: 150)), Row( children: [ Padding( padding: const EdgeInsets.only(top: 20, left: 20), child: Text('Your Interests', style: logintext), ), ], ), FutureBuilder( future: Get.put(APIService(Dio())).getInterest(token), builder: (context, AsyncSnapshot<ListModel> snapshot) { if (!snapshot.hasData) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } if (snapshot.hasError) { return Container(child: Text(snapshot.error.toString())); } return const SizedBox(); } return SingleChildScrollView( physics: const BouncingScrollPhysics(), child: Padding( padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 10), child: SizedBox( height: 120, child: GridView.builder( itemCount: snapshot.data!.data!.length, scrollDirection: Axis.vertical, gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( crossAxisCount: 3, childAspectRatio: 4 / 2), itemBuilder: (BuildContext context, int index) { Data data = snapshot.data!.data![index]; String currentId = data.id.toString(); bool isSelected = selectedInterestId == currentId; return InkWell( onTap: () { setState(() { // 更新选中状态:点击已选中项则取消,否则选中当前项 selectedInterestId = isSelected ? null : currentId; }); }, child: Container( margin: const EdgeInsets.symmetric(vertical: 10, horizontal: 5), decoration: BoxDecoration( // 动态设置背景色:选中时金色,未选中时白色 color: isSelected ? AppColors.golden : AppColors.purewhite, border: Border.all( color: AppColors.golden, width: 3), borderRadius: const BorderRadius.all(Radius.circular(20))), padding: const EdgeInsets.all(1), child: Center( child: Text( data.interest.toString(), style: TextStyle( fontSize: 25, // 可选:选中时文字改为白色,增强对比度 color: isSelected ? AppColors.purewhite : Colors.black), ), ), ), ); }, ), ), ), ); }, ), ]), ], ), ), ), ], ), ), ), );
补充说明
- 若
AppColors未定义golden,需添加对应颜色值,例如static const Color golden = Color(0xFFFFD700); - 可根据设计需求调整选中样式:比如仅修改边框粗细/颜色,而非背景色
- 如果需要用索引判断选中状态,可将
selectedInterestId替换为int? selectedIndex,逻辑保持一致
内容的提问来源于stack exchange,提问作者Jack
相关产品推荐
相关产品推荐

