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
相关产品推荐
相关产品推荐

