You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 03:32:44