From fab3eb21c2927fba62fd19186d1effdc28d2f0dd Mon Sep 17 00:00:00 2001 From: xster Date: Tue, 17 Sep 2019 11:09:18 -0700 Subject: [PATCH] Let Material BackButton have a custom onPressed handler (#39600) --- .../flutter/lib/src/cupertino/nav_bar.dart | 3 +- .../flutter/lib/src/material/back_button.dart | 21 +++++++++++-- .../test/material/back_button_test.dart | 31 +++++++++++++++++++ 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/packages/flutter/lib/src/cupertino/nav_bar.dart b/packages/flutter/lib/src/cupertino/nav_bar.dart index e11331e4aa4..19277a571eb 100644 --- a/packages/flutter/lib/src/cupertino/nav_bar.dart +++ b/packages/flutter/lib/src/cupertino/nav_bar.dart @@ -1259,7 +1259,8 @@ class CupertinoNavigationBarBackButton extends StatelessWidget { /// to pop the [Navigator]. /// /// It can, for instance, be used to pop the platform's navigation stack - /// instead of Flutter's [Navigator]. + /// via [SystemNavigator] instead of Flutter's [Navigator] in add-to-app + /// situations. /// /// Defaults to null. final VoidCallback onPressed; diff --git a/packages/flutter/lib/src/material/back_button.dart b/packages/flutter/lib/src/material/back_button.dart index 0c16f496237..956220a8f08 100644 --- a/packages/flutter/lib/src/material/back_button.dart +++ b/packages/flutter/lib/src/material/back_button.dart @@ -48,7 +48,8 @@ class BackButtonIcon extends StatelessWidget { /// /// A [BackButton] is an [IconButton] with a "back" icon appropriate for the /// current [TargetPlatform]. When pressed, the back button calls -/// [Navigator.maybePop] to return to the previous route. +/// [Navigator.maybePop] to return to the previous route unless a custom +/// [onPressed] callback is provided. /// /// When deciding to display a [BackButton], consider using /// `ModalRoute.of(context)?.canPop` to check whether the current route can be @@ -72,7 +73,7 @@ class BackButtonIcon extends StatelessWidget { class BackButton extends StatelessWidget { /// Creates an [IconButton] with the appropriate "back" icon for the current /// target platform. - const BackButton({ Key key, this.color }) : super(key: key); + const BackButton({ Key key, this.color, this.onPressed }) : super(key: key); /// The color to use for the icon. /// @@ -80,6 +81,16 @@ class BackButton extends StatelessWidget { /// which usually matches the ambient [Theme]'s [ThemeData.iconTheme]. final Color color; + /// An override callback to perform instead of the default behavior which is + /// to pop the [Navigator]. + /// + /// It can, for instance, be used to pop the platform's navigation stack + /// via [SytemNavigator] instead of Flutter's [Navigator] in add-to-app + /// situations. + /// + /// Defaults to null. + final VoidCallback onPressed; + @override Widget build(BuildContext context) { assert(debugCheckHasMaterialLocalizations(context)); @@ -88,7 +99,11 @@ class BackButton extends StatelessWidget { color: color, tooltip: MaterialLocalizations.of(context).backButtonTooltip, onPressed: () { - Navigator.maybePop(context); + if (onPressed != null) { + onPressed(); + } else { + Navigator.maybePop(context); + } }, ); } diff --git a/packages/flutter/test/material/back_button_test.dart b/packages/flutter/test/material/back_button_test.dart index 083777ff536..5044a3fef0d 100644 --- a/packages/flutter/test/material/back_button_test.dart +++ b/packages/flutter/test/material/back_button_test.dart @@ -34,6 +34,37 @@ void main() { expect(find.text('Home'), findsOneWidget); }); + testWidgets('BackButton onPressed overrides default pop behavior', (WidgetTester tester) async { + bool backPressed = false; + await tester.pumpWidget( + MaterialApp( + home: const Material(child: Text('Home')), + routes: { + '/next': (BuildContext context) { + return Material( + child: Center( + child: BackButton(onPressed: () => backPressed = true), + ), + ); + }, + }, + ) + ); + + tester.state(find.byType(Navigator)).pushNamed('/next'); + + await tester.pumpAndSettle(); + + await tester.tap(find.byType(BackButton)); + + await tester.pumpAndSettle(); + + // We're still on the second page. + expect(find.text('Home'), findsNothing); + // But the custom callback is called. + expect(backPressed, true); + }); + testWidgets('BackButton icon', (WidgetTester tester) async { final Key iOSKey = UniqueKey(); final Key androidKey = UniqueKey();