Repository: flutter
Issue: [Proposal]Allow transitions when reordering pages in Navigator.pages
Labels: c: new feature,framework,f: routes,c: proposal,P3,team-framework,triaged-framework

## Use case

When I reorder pages in `Navigator.pages`, I need a transition for the existing page in the stack becoming the top one. Currently `Navigator` is only animating entirely new pages on the stack and pages being removed from the stack.

Here is the code reordering two pages and the resulting animation, we see the transition only when the page is added for the first time but not on subsequent changes:

![JJEFp](https://user-images.githubusercontent.com/44893228/184640602-8fd56bde-40cc-44c5-bf61-2d2118c27c1b.gif)

<details>
  <summary>Code</summary>

```dart
import 'package:flutter/material.dart';

void main() => runApp(const MyApp());

final _notifier = ChangeNotifier();
final _pages = <Page>[Page1()];

class Page1 extends MaterialPage {
  Page1()
      : super(
          key: const ValueKey('Page1'),
          child: Scaffold(
            appBar: AppBar(title: const Text('Page1')),
            body: const Center(
              child: ElevatedButton(
                onPressed: _showPage2,
                child: Text('Show Page2'),
              ),
            ),
          ),
        );
}

class Page2 extends MaterialPage {
  Page2()
      : super(
          key: const ValueKey('Page2'),
          child: Scaffold(
            appBar: AppBar(title: const Text('Page2')),
            body: const Center(
              child: ElevatedButton(
                onPressed: _showPage1,
                child: Text('Show Page1'),
              ),
            ),
          ),
        );
}

void _showPage1() {
  for (final page in _pages) {
    if (page.key == const ValueKey('Page1')) {
      _pages.remove(page);
      break;
    }
  }
  _pages.add(Page1());
  _notifier.notifyListeners();
}

void _showPage2() {
  for (final page in _pages) {
    if (page.key == const ValueKey('Page2')) {
      _pages.remove(page);
      break;
    }
  }
  _pages.add(Page2());
  _notifier.notifyListeners();
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: HomeScreen(),
    );
  }
}

class HomeScreen extends StatelessWidget {
  const HomeScreen({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _notifier,
      builder: (_, __) {
        return Navigator(
          pages: [..._pages],
          transitionDelegate: const MyTransitionDelegate(),
          onPopPage: (route, result) {
            if (!route.didPop(result)) return false;

            return true;
          },
        );
      },
    );
  }
}
```
</details>

Alternative solutions so far are:

1. To change the key of the new page. But I need keys to track some things in the app.

2. To add a non-zero duration between removing and re-adding a page. But this is noticeable.

3. Use 3rd party solutions for animations. In my opinion, this is inconsistent. `Navigator.pages` encapsulates the diffing of the stack, so it is the first one to know the changes. If we need to track the reordering for 3rd party solutions, then we effectively re-write the `Navigator`.

## Proposal

`Navigator.transitionDelegate` seems like the right property to handle this. `TransitionDelegate` has `resolve` method to override transitions, but it is only called when a new route is pushed.

I propose to either call this method also when the order changes, or to add another method for that case (depending on how bad is the breaking change of additional calls to the existing method).