Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Janky animation when navigating away from variable-height stateful widget #184

Open
auradigitaldev opened this issue Apr 19, 2024 · 5 comments
Labels
bug Something isn't working in triage

Comments

@auradigitaldev
Copy link

Bug report

Describe the bug
First off, I love WoltModalSheet, it makes multi-page modals so easy!

However, I've been running into a pretty rough issue - whenever changing between modal pages where the first modal page is a StatefulWidget that varies in height based on its state, the animation between modals becomes extremely janky.

  • The modal will smoothly transition to a height that seems based on the difference in height between the StatefulWidget's default state and current state
  • Then the modal will abruptly snap to the height of the new modal page.

Here's a video to illustrate. At 0:08 I change the height of the first modal and then navigate to the second modal, which shows the bug:

screen-20240419-152521.mp4

Steps to reproduce

Steps to reproduce the behavior:

  1. Have a multi-page modal where the first page is a stateful widget whose height depends on its own state
  2. Update the height of the stateful widget
  3. Navigate to the next page of the multi-page modal
  4. Observe bug

Expected behavior

Expected to see a smooth transition between the heights of the current modal page and the next page.


Additional context

Below is the code for the example in the video. In my code I vary the height of a Container but this will work with anything that affects widget height, e.g. Visibility, etc, and still occurs even if you add smooth animations between heights. It will also work regardless of whether the second page has static or variable height.

/// The function that shows the multi-page modal
Future<void> showExampleModal(BuildContext context) {
  final currentPageNotifier = ValueNotifier(0);

  return WoltModalSheet.show(
    context: context,
    barrierDismissible: true,
    modalBarrierColor: Colors.black,
    useRootNavigator: true,
    pageIndexNotifier: currentPageNotifier,
    pageListBuilder: (BuildContext context) => [
      WoltModalSheetPage(
        child: VariableHeightWidget(
          goToOtherPage: () => currentPageNotifier.value = 1,
        ),
      ),
      WoltModalSheetPage(
        child: StaticHeightWidget(
            goToOtherPage: () => currentPageNotifier.value = 0),
      ),
    ],
  );
}

/// The first page of the modal (height depends on state)
class VariableHeightWidget extends StatefulWidget {
  const VariableHeightWidget({super.key, required this.goToOtherPage});

  final void Function() goToOtherPage;

  @override
  State<VariableHeightWidget> createState() => _VariableHeightWidgetState();
}

class _VariableHeightWidgetState extends State<VariableHeightWidget> {
  bool isBigBox = false;

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        GestureDetector(
          onTap: () => setState(() {
            isBigBox = !isBigBox;
          }),
          child: const Text('change height'),
        ),
        const SizedBox(height: 32),
        GestureDetector(
          onTap: widget.goToOtherPage,
          child: const Text('go to other page'),
        ),
        const SizedBox(height: 32),
        AnimatedContainer(
          duration: CustomDurations.slow500,
          height: isBigBox ? 400 : 100,
          color: Colors.red,
        ),
      ],
    );
  }
}

/// The second page of the modal (static height)
class StaticHeightWidget extends StatelessWidget {
  const StaticHeightWidget({
    super.key,
    required this.goToOtherPage,
  });

  final void Function() goToOtherPage;

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisSize: MainAxisSize.min,
      children: [
        GestureDetector(
          onTap: goToOtherPage,
          child: const Text('go to other page'),
        ),
        const SizedBox(height: 32),
        Container(
          height: 200,
          color: Colors.blue,
        ),
      ],
    );
  }
}

@auradigitaldev auradigitaldev added bug Something isn't working in triage labels Apr 19, 2024
@ulusoyca
Copy link
Collaborator

This is indeed a bug and needs investigation
image

@ibraheemalayan
Copy link

We’re experiencing the same issue and its disturbing.

Are there any updates ?

@ibraheemalayan
Copy link

@ulusoyca
Our use case details, might help identify the issue

We have a future builder that loads a list of items ( or illustration if empty ). Initially, it shows a loading indicator that has a certain fixed height. Switching to another page in the modal sheet works fine while it's loading (still on the initial size).

However, once the data loads and the height changes, switching pages causes a sudden change to the maximum height before switching to the next page.

Placing AnimatedSize widgets didn’t help.
Here’s a video with slow animation and children wrapped in AnimatedSize widgets.

WhatsApp.Video.2024-09-27.at.08.50.09.mp4

@ibraheemalayan
Copy link

Any updates on this bug ?

@Hamza-Nasser
Copy link

Hamza-Nasser commented Jan 1, 2025

@ibraheemalayan this bug is appearing only if there is more than on child in the main content, if you are placing your main content in a column then try to make that column with only one widget, this is not a solution but might be useful for debugging.
for example, the following code represents the first modal page, notice the change when placing one more sibling to the red container and without that sibling.
with a sibling:

  child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Container(
            height: 600,
            width: double.infinity,
            color: Colors.red,
          ),
          const _Link(),
        ],
      ),

As a result:

wolt_modal.webm

without the sibling (or omitting the column):

child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Container(
            height: 600,
            width: double.infinity,
            color: Colors.red,
          ),
        ],
      ),

As a result:

wolt_modal_trans.webm

[update] this is one of the scenarios that produces this issue, I have tried the same technique with different UI element rather than the container and the issue might happen even there is only one child in the column

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working in triage
Projects
None yet
Development

No branches or pull requests

4 participants