Repository: flutter
Issue: Add a `delay` argument to all implicitly animated widgets
Labels: c: new feature,framework,a: animation,c: proposal,P3,team-framework,triaged-framework

### 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.
```dart
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:
```dart
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),
            );
          },
        ),
      ),
    );
  }
}
```