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

Add a delay argument to all implicitly animated widgets #148628

Open
caseycrogers opened this issue May 19, 2024 · 0 comments
Open

Add a delay argument to all implicitly animated widgets #148628

caseycrogers opened this issue May 19, 2024 · 0 comments
Labels
a: animation Animation APIs c: new feature Nothing broken; request for a new capability c: proposal A detailed proposal for a change to Flutter framework flutter/packages/flutter repository. See also f: labels. P3 Issues that are less important to the Flutter project team-framework Owned by Framework team triaged-framework Triaged by Framework team

Comments

@caseycrogers
Copy link
Contributor

caseycrogers commented May 19, 2024

Use case

I have an implicitly animated widget where I want the transition animation to be delayed by a certain amount.

Here's a more specific/detailed example:

  1. I have N elements laid out in a column
  2. I I'm using AnimatedSwitcher (though you could also want this with any other implicitly animated widget) to animate in a new set of N elements
  3. I want to stagger the transition so that each element doesn't transition until the one before it has transitioned

Proposal

All implicitly animated widgets have an optional Duration delay named argument (AnimatedSwitcher, AnimatedContainer, etc).
If a non zero delay is sepcified, then the transitions for that widget start after waiting for the specified delay.

Here is an example of the effect I want to achieve.
https://github.com/flutter/flutter/assets/10675231/f2051141-5151-4777-8214-abf317b87c6d

Here's a code sample for how I achieved it. Note how hacky and complex the logic was.

class _FlipperDemo extends StatefulWidget {
  const _FlipperDemo();

  @override
  State<_FlipperDemo> createState() => _FlipperDemoState();
}

class _FlipperDemoState extends State<_FlipperDemo> {
  int offset = 0;

  static const Duration duration = Duration(milliseconds: 200);

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        setState(() {
          offset += 2;
        });
      },
      child: Column(
        children: List.generate(
          4,
          (i) {
            final Color color = [Colors.blue, Colors.red, Colors.green, Colors.yellow][(i + offset) % 4];
            return AnimatedSwitcher(
              // Have to multiply the duration by 4 to get the effect.
              duration: duration * 4,
              transitionBuilder: (child, animation) {
                // Some complex hackery to get the old widget to slide out while
                // the new widget slides in.
                // This is not entirely relevant to this feature request.
                final bool isTopWidget = child.key == ValueKey(color);
                // We'll use this int to stagger when the animations are
                // triggered. The outgoing widget's animation is played in
                // reverse so we need to invert the staggering on the incoming
                // widget to get them to match up.
                final int staggerStep = isTopWidget ? i : 3 - i;
                return SlideTransition(
                  child: child,
                  position: Tween(
                    begin: Offset(
                      child.key == ValueKey(color) ? 1 : -1,
                      0,
                    ),
                    end: const Offset(0, 0),
                  ).animate(
                    CurvedAnimation(
                      parent: animation,
                      // Gross hackery to the animations staggered one after
                      // the other.
                      curve: Interval(
                              staggerStep * .25,
                              .25 + staggerStep * .25,
                            ),
                    ),
                  ),
                );
              },
              child: Container(key: ValueKey(color), height: 100, color: color),
            );
          },
        ),
      ),
    );
  }
}

Here is what the code would look like with my proposal, note how much simpler the implementation is:

class _FlipperDemo extends StatefulWidget {
  const _FlipperDemo();

  @override
  State<_FlipperDemo> createState() => _FlipperDemoState();
}

class _FlipperDemoState extends State<_FlipperDemo> {
  int offset = 0;

  static const Duration duration = Duration(milliseconds: 200);

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        setState(() {
          offset += 2;
        });
      },
      child: Column(
        children: List.generate(
          4,
          (i) {
            final Color color = [Colors.blue, Colors.red, Colors.green, Colors.yellow][(i + offset) % 4];
            return AnimatedSwitcher(
              duration: duration,
              // Delay each widgets' transitions by an amount proportional to
              // its index in the stack.
              delay: duration*i,
              transitionBuilder: (child, animation) {
                return SlideTransition(
                  child: child,
                  position: Tween(
                    begin: Offset(
                      child.key == ValueKey(color) ? 1 : -1,
                      0,
                    ),
                    end: const Offset(0, 0),
                  ).animate(animation),
                );
              },
              child: Container(key: ValueKey(color), height: 100, color: color),
            );
          },
        ),
      ),
    );
  }
}
@caseycrogers caseycrogers changed the title Add a delay factor to all implicitly animated widgets Add a delay argument to all implicitly animated widgets May 19, 2024
@danagbemava-nc danagbemava-nc added in triage Presently being triaged by the triage team c: new feature Nothing broken; request for a new capability framework flutter/packages/flutter repository. See also f: labels. a: animation Animation APIs c: proposal A detailed proposal for a change to Flutter team-framework Owned by Framework team and removed in triage Presently being triaged by the triage team labels May 20, 2024
@goderbauer goderbauer added P3 Issues that are less important to the Flutter project triaged-framework Triaged by Framework team labels May 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a: animation Animation APIs c: new feature Nothing broken; request for a new capability c: proposal A detailed proposal for a change to Flutter framework flutter/packages/flutter repository. See also f: labels. P3 Issues that are less important to the Flutter project team-framework Owned by Framework team triaged-framework Triaged by Framework team
Projects
None yet
Development

No branches or pull requests

3 participants