Skip to content

[Proposed fix] Build scheduled during frame exception when using flutter-expandable package #30

@instance-id

Description

@instance-id

Hey there,
When using the flutter-expandable package along with draggable_scrollbars, within a ListView.separated, collapsing a card in my list caused the error listed below:

════════ Exception caught by rendering library ═════════════════════════════════════════════════════
The following assertion was thrown during performLayout():
Build scheduled during frame.

While the widget tree was being built, laid out, and painted, a new frame was scheduled to rebuild the widget tree.

This might be because setState() was called from a layout or paint callback. If a change is needed to the widget tree, it should be applied as the tree is being built. Scheduling a change for the subsequent frame instead results in an interface that lags behind by one frame. If this was done to make your build dependent on a size measured at layout time, consider using a LayoutBuilder, CustomSingleChildLayout, or CustomMultiChildLayout. If, on the other hand, the one frame delay is the desired effect, for example because this is an animation, consider scheduling the frame in a post-frame callback using SchedulerBinding.addPostFrameCallback or using an AnimationController to trigger the animation.

I have discovered that on line 417 of draggable_scrollbar, if instead of simply setState(), it is changed to the following with an addPostFrameCallback: The issue no longer occurs.

I am still fairly new to flutter, so I can't say for sure if this would have issues in any other cases, but it fixed my issue straight away.

	// Addition of addPostFrameCallback
    WidgetsBinding.instance.addPostFrameCallback((_) {
      setState(() {
        if (notification is ScrollUpdateNotification) {
          _barOffset += getBarDelta(
            notification.scrollDelta,
            barMaxScrollExtent,
            viewMaxScrollExtent,
          );

          if (_barOffset < barMinScrollExtent) {
            _barOffset = barMinScrollExtent;
          }
          if (_barOffset > barMaxScrollExtent) {
            _barOffset = barMaxScrollExtent;
          }

          _viewOffset += notification.scrollDelta;
          if (_viewOffset < widget.controller.position.minScrollExtent) {
            _viewOffset = widget.controller.position.minScrollExtent;
          }
          if (_viewOffset > viewMaxScrollExtent) {
            _viewOffset = viewMaxScrollExtent;
          }
        }

        if (notification is ScrollUpdateNotification ||
            notification is OverscrollNotification) {
          if (_thumbAnimationController.status != AnimationStatus.forward) {
            _thumbAnimationController.forward();
          }

          _fadeoutTimer?.cancel();
          _fadeoutTimer = Timer(widget.scrollbarTimeToFade, () {
            _thumbAnimationController.reverse();
            _labelAnimationController.reverse();
            _fadeoutTimer = null;
          });
        }
      });
    });

Thanks,
-id

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions