improve error message when herocontroller is shared by multiple navig… (#72904)
diff --git a/packages/flutter/lib/src/widgets/navigator.dart b/packages/flutter/lib/src/widgets/navigator.dart
index 0edd0f3..640832a 100644
--- a/packages/flutter/lib/src/widgets/navigator.dart
+++ b/packages/flutter/lib/src/widgets/navigator.dart
@@ -3425,8 +3425,28 @@
ServicesBinding.instance!.addPostFrameCallback((Duration timestamp) {
// We only check if this navigator still owns the hero controller.
if (_heroControllerFromScope == newHeroController) {
- assert(_heroControllerFromScope!._navigator == this);
- assert(previousOwner._heroControllerFromScope != newHeroController);
+ final bool hasHeroControllerOwnerShip = _heroControllerFromScope!._navigator == this;
+ if (!hasHeroControllerOwnerShip ||
+ previousOwner._heroControllerFromScope == newHeroController) {
+ final NavigatorState otherOwner = hasHeroControllerOwnerShip
+ ? previousOwner
+ : _heroControllerFromScope!._navigator!;
+ FlutterError.reportError(
+ FlutterErrorDetails(
+ exception: FlutterError(
+ 'A HeroController can not be shared by multiple Navigators. '
+ 'The Navigators that share the same HeroController are:\n'
+ '- $this\n'
+ '- $otherOwner\n'
+ 'Please create a HeroControllerScope for each Navigator or '
+ 'use a HeroControllerScope.none to prevent subtree from '
+ 'receiving a HeroController.'
+ ),
+ library: 'widget library',
+ stack: StackTrace.current,
+ ),
+ );
+ }
}
});
}
diff --git a/packages/flutter/test/widgets/navigator_test.dart b/packages/flutter/test/widgets/navigator_test.dart
index 4c14361..11bde97 100644
--- a/packages/flutter/test/widgets/navigator_test.dart
+++ b/packages/flutter/test/widgets/navigator_test.dart
@@ -2489,6 +2489,62 @@
expect(tester.takeException(), isAssertionError);
});
+ testWidgets('hero controller throws has correct error message', (WidgetTester tester) async {
+ final HeroControllerSpy spy = HeroControllerSpy();
+ await tester.pumpWidget(
+ HeroControllerScope(
+ controller: spy,
+ child: Directionality(
+ textDirection: TextDirection.ltr,
+ child: Stack(
+ children: <Widget>[
+ Navigator(
+ initialRoute: 'navigator1',
+ onGenerateRoute: (RouteSettings s) {
+ return MaterialPageRoute<void>(
+ builder: (BuildContext c) {
+ return const Placeholder();
+ },
+ settings: s,
+ );
+ },
+ ),
+ Navigator(
+ initialRoute: 'navigator2',
+ onGenerateRoute: (RouteSettings s) {
+ return MaterialPageRoute<void>(
+ builder: (BuildContext c) {
+ return const Placeholder();
+ },
+ settings: s,
+ );
+ },
+ ),
+ ],
+ ),
+ ),
+ ),
+ );
+
+ final dynamic exception = tester.takeException();
+ expect(exception, isFlutterError);
+ final FlutterError error = exception as FlutterError;
+ expect(
+ error.toStringDeep(),
+ equalsIgnoringHashCodes(
+ 'FlutterError\n'
+ ' A HeroController can not be shared by multiple Navigators. The\n'
+ ' Navigators that share the same HeroController are:\n'
+ ' - NavigatorState#00000(tickers: tracking 1 ticker)\n'
+ ' - NavigatorState#00000(tickers: tracking 1 ticker)\n'
+ ' Please create a HeroControllerScope for each Navigator or use a\n'
+ ' HeroControllerScope.none to prevent subtree from receiving a\n'
+ ' HeroController.\n'
+ ''
+ ),
+ );
+ });
+
group('Page api', (){
Widget buildNavigator({
required List<Page<dynamic>> pages,