Flutter技术问题:无法动态更新列表Tile选中状态的解决方法
解决BottomSheet中列表Tile点击后无法更新选中状态的问题
你的问题根源在于:showModalBottomSheet的内容是在点击触发时通过builder创建的,它属于独立的上下文环境,父组件的setState只会刷新父组件的UI,不会重新执行这个builder函数,所以里面的isThisSelected值不会跟着_selectedIndex的变化更新,自然不会重绘Tile的选中样式。
这里给你两种简单的解决方式:
方法一:用StatefulBuilder包裹BottomSheet内容
这种方式改动最小,不需要拆分组件,直接在BottomSheet内部维护局部状态的更新:
@override Widget build(BuildContext context) { return Column( children: <Widget>[ Row( children: <Widget>[ Container( child: GestureDetector( onTap: () { // 把当前选中索引传递给BottomSheet int currentSelected = _selectedIndex; showModalBottomSheet( context: context, builder: (BuildContext context) { return StatefulBuilder( builder: (context, setStateSheet) { return SingleChildScrollView( child: Column( children: List<Widget>.generate( _formattedCurrencies.length, (int index) { final bool isThisSelected = index == currentSelected; return Container( child: SelectableTile( isSelected: isThisSelected, onTap: () { // 先更新父组件的状态 setState(() { _selectedIndex = index; }); // 再更新BottomSheet内部的状态,触发重绘 setStateSheet(() { currentSelected = index; }); // 如果需要点击后关闭BottomSheet,加上这句 // Navigator.pop(context); }, ), ); }, ), ), ); }, ); }, ); }, child: const Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text('currency'), ], ), ), ), ], ), ], ); }
方法二:将BottomSheet内容抽为独立StatefulWidget
如果后续BottomSheet的逻辑更复杂,推荐把它拆成单独的组件,让组件自己管理选中状态,通过回调和父组件同步:
// 独立的BottomSheet组件 class CurrencySelectBottomSheet extends StatefulWidget { final int initialSelectedIndex; final List<String> currencies; final ValueChanged<int> onSelected; const CurrencySelectBottomSheet({ super.key, required this.initialSelectedIndex, required this.currencies, required this.onSelected, }); @override State<CurrencySelectBottomSheet> createState() => _CurrencySelectBottomSheetState(); } class _CurrencySelectBottomSheetState extends State<CurrencySelectBottomSheet> { late int _selectedIndex; @override void initState() { super.initState(); _selectedIndex = widget.initialSelectedIndex; } @override Widget build(BuildContext context) { return SingleChildScrollView( child: Column( children: List<Widget>.generate( widget.currencies.length, (int index) { final bool isThisSelected = index == _selectedIndex; return Container( child: SelectableTile( isSelected: isThisSelected, onTap: () { setState(() { _selectedIndex = index; }); widget.onSelected(index); // Navigator.pop(context); }, ), ); }, ), ), ); } } // 父组件中调用 @override Widget build(BuildContext context) { return Column( children: <Widget>[ Row( children: <Widget>[ Container( child: GestureDetector( onTap: () { showModalBottomSheet( context: context, builder: (BuildContext context) { return CurrencySelectBottomSheet( initialSelectedIndex: _selectedIndex, currencies: _formattedCurrencies, onSelected: (index) { setState(() { _selectedIndex = index; }); }, ); }, ); }, child: const Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text('currency'), ], ), ), ), ], ), ], ); }
两种方法都能解决你的问题,第一种适合快速修复,第二种更利于代码维护。
内容的提问来源于stack exchange,提问作者Fi Li Ppo
相关产品推荐
相关产品推荐

