Flutter实现水平可滚动Chip 选中联动下方内容及查看全部功能
Flutter Chip组功能实现代码调整方案
核心调整对应你提的3个需求:
- 替换原有Wrap嵌套垂直ListView的Chip布局,改用横向
ListView承载Chip组件,实现水平滚动效果;使用ChoiceChip替代基础Chip,原生支持选中态样式 - 新增独立变量
_selectedChipIndex存储当前选中的Chip下标,和底部导航栏的选中索引逻辑拆分,避免状态冲突;点击Chip时更新下标,驱动下方内容区渲染对应分类的数据 - 在Chip列表首位加入「查看全部」选项,选中时渲染全量分类数据
- 修复原代码中双Expanded嵌套导致的布局溢出问题,移除冗余的未绑定逻辑的PageView和色块列表,直接将内容渲染和Chip选中状态绑定
调整后完整可运行代码
import 'package:flutter/material.dart'; import 'package:mad_ezee_app/constants.dart'; class HomeScreen extends StatefulWidget { const HomeScreen({Key? key}) : super(key: key); @override State<HomeScreen> createState() => _HomeScreenState(); } class _HomeScreenState extends State<HomeScreen> { // 底部导航栏选中索引 int _selectedNavIndex = 0; // Chip选中索引,-1为初始未选中状态,0对应「查看全部」 int _selectedChipIndex = -1; PageController pageController = PageController(); // Chip分类列表 List<String> chipList = ["查看全部", "choice 1", "choice 2", "choice 3", "choice 4", "choice 5"]; // 每个Chip对应展示的内容色块,索引0为全量数据 List<List<Color>> chipRelatedContent = [ [Colors.red, Colors.blue, Colors.white, Colors.yellow, Colors.green, Colors.orange], [Colors.red], [Colors.blue], [Colors.white], [Colors.yellow], [Colors.green], [Colors.orange], ]; void onNavTapped(int index){ setState(() { _selectedNavIndex = index; }); pageController.jumpToPage(index); } void onChipSelected(int index) { setState(() { _selectedChipIndex = index; }); } @override Widget build(BuildContext context) { return Scaffold( body: Column( mainAxisSize: MainAxisSize.min, children:[ // 顶部地址、功能按钮栏 Container( margin: EdgeInsets.only(top:45,bottom: 15), padding: EdgeInsets.only(left: 20,right: 20), child:Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children:[ Text("Bengaluru"), Text("R.T Nagar") ] ), Container( width: 45, height:45, child: Icon(Icons.search,color: Colors.white,), decoration: BoxDecoration( borderRadius: BorderRadius.circular(15), color:TimePassColor.APP_COLOR ), ), Container( width: 45, height:45, child: Icon(Icons.notifications,color: Colors.white,), decoration: BoxDecoration( borderRadius: BorderRadius.circular(15), color:TimePassColor.APP_COLOR ), ), ] ) ), // 水平滚动Chip组 SizedBox( height: 50, child: ListView.separated( scrollDirection: Axis.horizontal, padding: EdgeInsets.symmetric(horizontal: 20), itemCount: chipList.length, separatorBuilder: (context, index) => SizedBox(width: 8), itemBuilder: (context, index) { return ChoiceChip( label: Text(chipList[index]), selected: _selectedChipIndex == index, onSelected: (val) => onChipSelected(index), ); }, ), ), // 联动展示的内容区 Expanded( child: _selectedChipIndex == -1 ? Center(child: Text("请选择分类查看内容")) : ListView( scrollDirection: Axis.horizontal, padding: EdgeInsets.symmetric(horizontal: 20, vertical: 15), children: chipRelatedContent[_selectedChipIndex].map((itemColor) { return Container( width: 160, margin: EdgeInsets.only(right: 10), decoration: BoxDecoration( color: itemColor, borderRadius: BorderRadius.circular(12) ), ); }).toList(), ), ), ] ), bottomNavigationBar: BottomNavigationBar( items: const <BottomNavigationBarItem> [ BottomNavigationBarItem(icon: Icon(Icons.home),label:'Home'), BottomNavigationBarItem(icon: Icon(Icons.cleaning_services),label:'House Keeping'), BottomNavigationBarItem(icon: Icon(Icons.search),label:'Search'), BottomNavigationBarItem(icon: Icon(Icons.account_balance_wallet),label:'Wallet'), BottomNavigationBarItem(icon: Icon(Icons.bookmarks),label:'Bookmarked'), BottomNavigationBarItem(icon: Icon(Icons.local_convenience_store),label:'Store'), BottomNavigationBarItem(icon: Icon(Icons.notifications),label:'Notifications'), BottomNavigationBarItem(icon: Icon(Icons.assessment),label:'Stats'), BottomNavigationBarItem(icon: Icon(Icons.person),label:'Profile'), ], currentIndex: _selectedNavIndex, selectedItemColor: Colors.blue, unselectedItemColor: Colors.grey, type: BottomNavigationBarType.fixed, onTap: onNavTapped, ) ); } }
补充说明
如果需要打开页面默认展示全量数据,直接将
_selectedChipIndex的初始值从-1改为0即可。如果需要保留原代码中的PageView做垂直页面切换,只需将内容区的横向ListView替换为PageView,将页面children数据源和_selectedChipIndex绑定即可实现联动。原代码中底部导航栏存在两个重复的Notifications标签,调整时将第二个改为了Stats,可根据实际需求自行修改。
内容的提问来源于stack exchange,提问作者Sachin Rajput
相关产品推荐
相关产品推荐

