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

Flutter中点击ListTile后选中状态不更新,如何解决?

Flutter ListTile点击后选中状态不更新问题解决

问题描述

开发Flutter应用时,使用ListTile展示录音列表,点击ListTile尝试更新选中状态,但UI未同步更新。控制台打印显示_selectedIndex已更新,但ListTile的selected状态无变化。相关代码如下:

Container buildPhraseCard(PhraseCard phrase) {

  int _selectedIndex = 0;

  return Container(
    margin: EdgeInsets.all(8),
    child: Column(
      children: [
        SizedBox(
          height: 32,
        ),
        ListTile(
          title: Text(
            phrase.phrase,
            style: TextStyle(
              fontSize: 24,
              fontWeight: FontWeight.w300,
            ),
          ),
          trailing: IconButton(onPressed: () {}, icon: Icon(Icons.closed_caption_disabled)),
        ),
        ListTile(
          title: const Text("お手本を再生"),
          leading: IconButton(onPressed: () {}, icon: Icon(Icons.hearing)),
        ),
        Divider(),
        Column(
          children: phrase.userPath.values.toList().asMap().entries.map((entry) {
            final index = entry.key;
            final phrase = entry.value;
            return ListTile(
              onTap: () {
                setState(() {
                  _selectedIndex = index;
                });
              },
              selected: index == _selectedIndex,
              title: Text("${index + 1}回目の発音"),
              leading: IconButton(onPressed: () {}, icon: Icon(Icons.play_arrow)),
              trailing: IconButton(onPressed: () {}, icon: Icon(Icons.feedback)),
            );
          }).toList(),
        ),
        ListTile(
          title: const Text("3回目を録音"),
          leading: IconButton(onPressed: () {}, icon: Icon(Icons.mic)),
        ),
        Divider(),
        SizedBox(
          height: 24,
        ),
        Text(
          '総合スコア',
          style: TextStyle(
            fontSize: 16,
            fontWeight: FontWeight.w100,
          ),
        ),
        SizedBox(
          height: 16,
        ),
        Text(
          phrase.userPath.values.elementAt(_selectedIndex).toString(),
          style: TextStyle(
            fontSize: 80,
            fontWeight: FontWeight.w100,
          ),
        ),
        SizedBox(
          height: 16,
        ),
      ],
    ),
  );
}

问题原因

_selectedIndex被定义在buildPhraseCard方法内部,属于局部变量。每次调用setState触发UI重建时,buildPhraseCard会重新执行,局部变量_selectedIndex会被重新初始化为0。这就导致虽然点击时临时修改了变量值,但重建后又回到初始值,UI自然不会更新选中状态。

解决方案

将_selectedIndex提升为State类的成员变量,这样它的值会在State实例的生命周期中保持,不会随build方法的执行被重置。

修改步骤:

  1. 在你的State类顶部定义_selectedIndex:
class YourWidgetState extends State<YourWidget> {
  // 把变量移到这里,作为State成员
  int _selectedIndex = 0;

  // 其他代码...
}
  1. 删除buildPhraseCard方法内部的int _selectedIndex = 0;,直接使用State类的成员变量。

修改后的代码片段:

class YourWidgetState extends State<YourWidget> {
  int _selectedIndex = 0; // 成员变量

  Container buildPhraseCard(PhraseCard phrase) {
    // 移除局部变量定义
    return Container(
      // ... 原有代码不变
      child: Column(
        children: [
          // ... 其他组件不变
          Column(
            children: phrase.userPath.values.toList().asMap().entries.map((entry) {
              final index = entry.key;
              final phrase = entry.value;
              return ListTile(
                onTap: () {
                  setState(() {
                    _selectedIndex = index; // 使用成员变量
                  });
                },
                selected: index == _selectedIndex, // 对比成员变量
                // ... 其他属性不变
              );
            }).toList(),
          ),
          // ... 其他组件不变
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    // ... 你的build方法
  }
}

这样修改后,点击ListTile时通过setState更新成员变量_selectedIndex,触发UI重建时,变量值会保留最新状态,ListTile的selected属性就能正确匹配,选中状态也会同步更新。

内容的提问来源于stack exchange,提问作者ぷにもち

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 01:22:05