app bar leading back button should not change if the route is popped (#71944)
diff --git a/packages/flutter/lib/src/material/app_bar.dart b/packages/flutter/lib/src/material/app_bar.dart
index b57b7a4..e2dedcd 100644
--- a/packages/flutter/lib/src/material/app_bar.dart
+++ b/packages/flutter/lib/src/material/app_bar.dart
@@ -709,6 +709,8 @@
Scaffold.of(context).openEndDrawer();
}
+ bool? hadBackButtonWhenRouteWasActive;
+
@override
Widget build(BuildContext context) {
assert(!widget.primary || debugCheckHasMediaQuery(context));
@@ -721,7 +723,11 @@
final bool hasDrawer = scaffold?.hasDrawer ?? false;
final bool hasEndDrawer = scaffold?.hasEndDrawer ?? false;
- final bool canPop = parentRoute?.canPop ?? false;
+ hadBackButtonWhenRouteWasActive ??= false;
+ if (parentRoute?.isActive == true) {
+ hadBackButtonWhenRouteWasActive = parentRoute!.canPop;
+ }
+ assert(hadBackButtonWhenRouteWasActive != null);
final bool useCloseButton = parentRoute is PageRoute<dynamic> && parentRoute.fullscreenDialog;
final double toolbarHeight = widget.toolbarHeight ?? kToolbarHeight;
@@ -790,7 +796,7 @@
tooltip: MaterialLocalizations.of(context).openAppDrawerTooltip,
);
} else {
- if (!hasEndDrawer && canPop)
+ if (!hasEndDrawer && hadBackButtonWhenRouteWasActive!)
leading = useCloseButton ? const CloseButton() : const BackButton();
}
}
diff --git a/packages/flutter/lib/src/widgets/routes.dart b/packages/flutter/lib/src/widgets/routes.dart
index 3ac1927..17ef544 100644
--- a/packages/flutter/lib/src/widgets/routes.dart
+++ b/packages/flutter/lib/src/widgets/routes.dart
@@ -1460,7 +1460,7 @@
/// When this changes, if the route is visible, the route will
/// rebuild, and any widgets that used [ModalRoute.of] will be
/// notified.
- bool get canPop => !isFirst || willHandlePopInternally;
+ bool get canPop => isActive && (!isFirst || willHandlePopInternally);
// Internals
diff --git a/packages/flutter/test/material/app_bar_test.dart b/packages/flutter/test/material/app_bar_test.dart
index af4283c..4ba2602 100644
--- a/packages/flutter/test/material/app_bar_test.dart
+++ b/packages/flutter/test/material/app_bar_test.dart
@@ -1122,6 +1122,97 @@
expect(find.byIcon(Icons.menu), findsNothing);
});
+ testWidgets('AppBar does not update the leading if a route is popped case 1', (WidgetTester tester) async {
+ final Page<void> page1 = MaterialPage<void>(
+ key: const ValueKey<String>('1'),
+ child: Scaffold(
+ key: const ValueKey<String>('1'),
+ appBar: AppBar(),
+ )
+ );
+ final Page<void> page2 = MaterialPage<void>(
+ key: const ValueKey<String>('2'),
+ child: Scaffold(
+ key: const ValueKey<String>('2'),
+ appBar: AppBar(),
+ )
+ );
+ List<Page<void>> pages = <Page<void>>[ page1 ];
+ await tester.pumpWidget(
+ MaterialApp(
+ home: Navigator(
+ pages: pages,
+ onPopPage: (Route<dynamic> route, dynamic result) => false,
+ ),
+ ),
+ );
+ expect(find.byType(BackButton), findsNothing);
+ // Update pages
+ pages = <Page<void>>[ page2 ];
+ await tester.pumpWidget(
+ MaterialApp(
+ home: Navigator(
+ pages: pages,
+ onPopPage: (Route<dynamic> route, dynamic result) => false,
+ ),
+ ),
+ );
+ expect(find.byType(BackButton), findsNothing);
+ });
+
+ testWidgets('AppBar does not update the leading if a route is popped case 2', (WidgetTester tester) async {
+ final Page<void> page1 = MaterialPage<void>(
+ key: const ValueKey<String>('1'),
+ child: Scaffold(
+ key: const ValueKey<String>('1'),
+ appBar: AppBar(),
+ )
+ );
+ final Page<void> page2 = MaterialPage<void>(
+ key: const ValueKey<String>('2'),
+ child: Scaffold(
+ key: const ValueKey<String>('2'),
+ appBar: AppBar(),
+ )
+ );
+ List<Page<void>> pages = <Page<void>>[ page1, page2 ];
+ await tester.pumpWidget(
+ MaterialApp(
+ home: Navigator(
+ pages: pages,
+ onPopPage: (Route<dynamic> route, dynamic result) => false,
+ ),
+ ),
+ );
+ // The page2 should have a back button
+ expect(
+ find.descendant(
+ of: find.byKey(const ValueKey<String>('2')),
+ matching: find.byType(BackButton),
+ ),
+ findsOneWidget
+ );
+ // Update pages
+ pages = <Page<void>>[ page1 ];
+ await tester.pumpWidget(
+ MaterialApp(
+ home: Navigator(
+ pages: pages,
+ onPopPage: (Route<dynamic> route, dynamic result) => false,
+ ),
+ ),
+ );
+ await tester.pump(const Duration(milliseconds: 10));
+ // The back button should persist during the pop animation.
+ expect(
+ find.descendant(
+ of: find.byKey(const ValueKey<String>('2')),
+ matching: find.byType(BackButton),
+ ),
+ findsOneWidget
+ );
+ });
+
testWidgets('AppBar ink splash draw on the correct canvas', (WidgetTester tester) async {
// This is a regression test for https://github.com/flutter/flutter/issues/58665
final Key key = UniqueKey();