Search code examples
flutterdartstate-management

Flutter avoid widget rebuild on collapsing/expanding ExpansionPanelList


In ExpansionPanelList, I have a problem of rebuilding widget when I expand/collapse it.

The problem is here:

expansionCallback: (int index, bool isExpanded) {
  setState(() {
    _profileExpansionStateMap[_profileExpansionStateMap.keys.toList()[index]] = !isExpanded;
  });
},

I changed it to use Bloc state management to solve, but that has same behavior with setState(). Is there any way to avoid rebuilding widget tree? I can't use Selector widget as I don't think it would help me here.

import 'package:flutter/material.dart';
void main()=>runApp(MaterialApp(home: Home(),));

class Home extends StatefulWidget {
  @override
  State<StatefulWidget> createState() =>HomeState();

}

class HomeState extends State<Home> {
  Map<String, bool> _profileExpansionStateMap = Map<String, bool>();

  @override
  void initState() {
    super.initState();
    _profileExpansionStateMap = {
      "UserInformation": false,
      "UserWeight": false,
      "UserGeneralInformation": false,
    };
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title:Text('ExpansionPanel')),
      body: SingleChildScrollView(
        child: Container(
          padding: EdgeInsets.all(20.0),
          child:ExpansionPanelList(
            expansionCallback: (int index, bool isExpanded) {
              setState(() {
                _profileExpansionStateMap[_profileExpansionStateMap.keys.toList()[index]] = !isExpanded;
              });
            },
            children: <ExpansionPanel>[
              ExpansionPanel(
                  headerBuilder: (BuildContext context, bool isExpanded) {
                    return Container(
                      height: 80.0,
                      child: Text('aaaaaaaa'),
                    );
                  },
                  body: Container(child:Text('aaaaaaaa')),
                  isExpanded: _profileExpansionStateMap["UserInformation"]),
              ExpansionPanel(
                  headerBuilder: (BuildContext context, bool isExpanded) {
                    return Container(
                      height: 80.0,
                      child: Text('bbbbbbbbbbbb'),
                    );
                  },
                  body: Container(child:Text('bbbbbbbbbbbb')),
                  isExpanded: _profileExpansionStateMap["UserWeight"]),
              ExpansionPanel(
                  headerBuilder: (BuildContext context, bool isExpanded) {
                    return Container(
                      height: 80.0,
                      child: Text('ccccccccc'),
                    );
                  },
                  body: Container(child:Text('ccccccccc')),
                  isExpanded: _profileExpansionStateMap["UserGeneralInformation"]),
            ],
          )
        ),
      ),
    );
  }
}

Solution

  • ExpansionPanelList.expansionCallback(...) is a method that gets called whenever you tap on arrow buttons inside your ExpansionPanelList to expand/collapse it.

    In this method you are actually supposed to setup your bool values passed to isExpanded of ExpansionPanel thus requiring you to call setState(...).

    If you, however, have issues with this, then it clearly indicates there is something wrong with your code. So, there is no need to avoid rebuilding the widget state.