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

Flutter中ExpansionPanel无法展开问题求助

问题:ExpansionPanel无法展开,isExpanded始终为false

将ExpansionPanel嵌套在ExpansionPanelList内时,点击面板无法展开,且每次检查ExpansionPanel的isExpanded值均为false。尝试用单独的expanded列表管理状态,结果依旧。

问题代码

import 'package:flutter/material.dart';
import 'package:tax_calculator/core/values/info-strings.dart';
import '../core/values/app_colors.dart';

class InformationPage extends StatelessWidget {
  const InformationPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: AppColors.colorPrimary,
        title: const Text("Information"),
        centerTitle: true,
      ),
      body: const SafeArea(
        child: SingleChildScrollView(
          child: Padding(
            padding: EdgeInsets.all(20.0),
            child: Center(
              child: BuildExpansionPanel(),
            ),
          ),
        ),
      ),
    );
  }
}

class BuildExpansionPanel extends StatefulWidget {
  const BuildExpansionPanel({Key? key}) : super(key: key);

  @override
  State<StatefulWidget> createState() => _BuildExpansionPanelState();
}

class _BuildExpansionPanelState extends State<BuildExpansionPanel> {
  final List<Item> _list = generateItems(information.length);
  List<bool> expanded = [false, false];

  @override
  Widget build(BuildContext context) {
    return ExpansionPanelList(
      elevation: 1,
      expandedHeaderPadding: const EdgeInsets.all(10),

      expansionCallback: (int index, bool isExpanded) {
        setState(() {
          _list[index].isExpanded = !isExpanded;
          print('$index and $isExpanded');
        });
      },
      children: _list.map<ExpansionPanel>((Item item) {
        return ExpansionPanel(
          canTapOnHeader: true,
          headerBuilder: (BuildContext context, bool isExpanded) {
            print('In Panel $isExpanded');
            return ListTile(
              title: Text(item.headerValue),
            );
          },
          body: ListTile(
            title: Text(item.expandedValue),
          ),
          isExpanded: item.isExpanded,
        );
      }).toList(),
    );
  }
}

class Item {
  Item({
    required this.expandedValue,
    required this.headerValue,
  });

  String expandedValue;
  String headerValue;
  bool isExpanded = false;
}

List<Item> generateItems(int numberOfItems) {
  return List.generate(numberOfItems, (int index) {
    return Item(
      headerValue: information[index].title,
      expandedValue: information[index].body,
    );
  });
}

问题根源

核心问题是父组件中BuildExpansionPanel被声明为const:

child: const BuildExpansionPanel(),

对于StatefulWidget而言,const修饰会强制widget保持不可变状态。即使在State中调用setState修改内部状态,Flutter会认为widget未发生变化,不会触发UI重建,导致面板的展开状态无法更新。

修复方案

1. 移除const修饰符

修改InformationPage中的代码,去掉BuildExpansionPanel及父级相关widget的const(子widget非const时,父级const无法保留):

body: SafeArea(
  child: SingleChildScrollView(
    child: Padding(
      padding: const EdgeInsets.all(20.0),
      child: Center(
        child: BuildExpansionPanel(),
      ),
    ),
  ),
),

2. 优化状态更新逻辑(可选)

将expansionCallback中的状态更新逻辑改为直接取反当前item的isExpanded值,逻辑更直观:

expansionCallback: (int index, bool isExpanded) {
  setState(() {
    _list[index].isExpanded = !_list[index].isExpanded;
    print('$index and ${_list[index].isExpanded}');
  });
},

修复后完整代码

import 'package:flutter/material.dart';
import 'package:tax_calculator/core/values/info-strings.dart';
import '../core/values/app_colors.dart';

class InformationPage extends StatelessWidget {
  const InformationPage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: AppColors.colorPrimary,
        title: const Text("Information"),
        centerTitle: true,
      ),
      body: SafeArea(
        child: SingleChildScrollView(
          child: Padding(
            padding: const EdgeInsets.all(20.0),
            child: Center(
              child: BuildExpansionPanel(),
            ),
          ),
        ),
      ),
    );
  }
}

class BuildExpansionPanel extends StatefulWidget {
  const BuildExpansionPanel({Key? key}) : super(key: key);

  @override
  State<StatefulWidget> createState() => _BuildExpansionPanelState();
}

class _BuildExpansionPanelState extends State<BuildExpansionPanel> {
  final List<Item> _list = generateItems(information.length);

  @override
  Widget build(BuildContext context) {
    return ExpansionPanelList(
      elevation: 1,
      expandedHeaderPadding: const EdgeInsets.all(10),
      expansionCallback: (int index, bool isExpanded) {
        setState(() {
          _list[index].isExpanded = !_list[index].isExpanded;
          print('$index and ${_list[index].isExpanded}');
        });
      },
      children: _list.map<ExpansionPanel>((Item item) {
        return ExpansionPanel(
          canTapOnHeader: true,
          headerBuilder: (BuildContext context, bool isExpanded) {
            print('In Panel $isExpanded');
            return ListTile(
              title: Text(item.headerValue),
            );
          },
          body: ListTile(
            title: Text(item.expandedValue),
          ),
          isExpanded: item.isExpanded,
        );
      }).toList(),
    );
  }
}

class Item {
  Item({
    required this.expandedValue,
    required this.headerValue,
  });

  String expandedValue;
  String headerValue;
  bool isExpanded = false;
}

List<Item> generateItems(int numberOfItems) {
  return List.generate(numberOfItems, (int index) {
    return Item(
      headerValue: information[index].title,
      expandedValue: information[index].body,
    );
  });
}

内容的提问来源于stack exchange,提问作者Anik Rahman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 02:40:56