RobbB
RobbB

Reputation: 1354

Accordion widget closes automatically (is rebuilt) on state change - how to avoid this | Flutter

I'm using this beautiful Accordion package.

I have a few different situations where state changes in Accordion child widgets are causing entire Accordion widget rebuilds which in turn causes accordions to close on state change. My example below is highly simplified. The CustomRadioButton enforcedValue is the state change.

For example, a radio button is tapped, the state changes and the accordion closes. Upon reopening the accordion the state is updated.

Of course this is undesired, the entire accordion parent should not rebuild. I'm using Riverpod, the whole point of riverpod is to enact only rebuilds of child widgets that require it and not rebuild larger parents.

I have tried messing around with keys but I don't have any conclusive good changes to report along this line.

What am I doing wrong here? Is there something I can change while maintaining widget reusability as I currently have?

class Page extends ConsumerWidget {
  const Page({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // Exemplary boolean visibility values (not important for this, just showing for example)
    bool one = true;
    bool two = true;
    bool three = true;

    return SingleChildScrollView(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        mainAxisSize: MainAxisSize.min,
        children: [
          pulldownExample(context, ref, null),
          Visibility(visible: one, child: pulldownExample(context, ref, 0)),
          Visibility(visible: two, child: pulldownExample(context, ref, 1)),
          Visibility(visible: three, child: pulldownExample(context, ref, 2)),
        ],
      ),
    );
  }

  // FP magnitude notification pulldown
  Widget pulldownExample(
    BuildContext context,
    WidgetRef ref,
    int? index,
  ) {
    return Accordion(
      scaleWhenAnimating: false,
      openAndCloseAnimation: true,
      flipRightIconIfOpen: true,
      disableScrolling: true,
      children: [
        AccordionSection(
          header: Text('DYNAMIC HEADER TEXT'),
          content: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            mainAxisSize: MainAxisSize.min,
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Row(
                mainAxisAlignment: MainAxisAlignment.start,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  CustomRadioButton(
                    enforcedValue: ref.watch(exampleState).valueOne, // Trouble here when this state changes
                    onTap: (_) => onTapLogic(),
                  ),
                  const SizedBox(width: 8),
                  Text('ONE'),
                ],
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.start,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  CustomRadioButton(
                    enforcedValue: ref.watch(exampleState).valueTwo, // Trouble here when this state changes
                    onTap: (_) => onTapLogic(),
                  ),
                  const SizedBox(width: 8),
                  Text('TWO'),
                ],
              ),
              Row(
                mainAxisAlignment: MainAxisAlignment.start,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  CustomRadioButton(
                    enforcedValue: ref.watch(exampleState).valueThree, // Trouble here when this state changes
                    onTap: (_) => onTapLogic(),
                  ),
                  const SizedBox(width: 8),
                  Text('THREE'),
                ],
              ),
            ],
          ),
        ),
      ],
    );
  }
}

Upvotes: 1

Views: 818

Answers (1)

Ruble
Ruble

Reputation: 4844

First, your pulldownExample method needs to be converted into a separate ConsumerWidget widget with the required fields. This will optimize rebuilds.

Second, you can use the Consumer widget inside the build method to rebuild only those parts of the tree that need to be rebuilt. Also consider using select for the exampleState provider.

Links:

Upvotes: 2

Related Questions