marcglasberg / back_button_interceptor

Flutter Package: May be used to intercept the Android back-button, as an alternative to `WillPopScope`.
BSD 2-Clause "Simplified" License
105 stars 21 forks source link

pub package

back_button_interceptor

In simple cases, when you need to intercept the Android back-button, you usually add WillPopScope to your widget tree. However, when developing stateful widgets that interact with the back button, it's more convenient to use the BackButtonInterceptor.

You may add interceptor functions to be called when the back button is tapped. These functions may perform some useful work, and then, if any of them return true, the default button process (usually popping a Route) will not be fired.

Android 13

To make it work on Android 13 and up, set this to false in the Android manifest:

android:enableOnBackInvokedCallback="false"

In more detail

All added functions are called, in order. If any function returns true, the combined result is true, and the default button process will NOT be fired. Only if all functions return false (or null), the combined result is false, and the default button process will be fired.

Optionally, you may provide a z-index. Functions with a valid z-index will be called before functions with a null z-index, and functions with larger z-index will be called first. When they have the same z-index, functions added last are called first.

Each function gets the boolean stopDefaultButtonEvent that indicates the current combined result from all the previous functions. So, if some function doesn't want to fire if some other previous function already fired, it can do:

if (stopDefaultButtonEvent) return false;

The same result may be obtained if the optional ifNotYetIntercepted parameter is true. Then the function will only be called if all previous functions returned false (that is, if stopDefaultButtonEvent is false).

Notes


Examples

Intercepting

@override
void initState() {
   super.initState();
   BackButtonInterceptor.add(myInterceptor);
}

@override
void dispose() {
   BackButtonInterceptor.remove(myInterceptor);
   super.dispose();
}

bool myInterceptor(bool stopDefaultButtonEvent, RouteInfo info) {
   print("BACK BUTTON!"); // Do some stuff.
   return true;
}

Named function and z-index

@override
void initState() {
   super.initState();
   BackButtonInterceptor.add(myInterceptor, zIndex:2, name:"SomeName");
}

@override
void dispose() {
   BackButtonInterceptor.removeByName("SomeName");
   super.dispose();
}

bool myInterceptor(bool stopDefaultButtonEvent, RouteInfo info) {
   print("BACK BUTTON!"); // Do some stuff.
   return true;
}

Runnable Examples

  1. main

    Intercepts the back-button and prints a string to the console.

  2. main

    Intercepts the back-button and prints a string to the console, by using an async interceptor function.

  3. main_complex_example

    The first screen has a button which opens a second screen. The second screen has 3 red squares. By tapping the Android back-button (or the "pop" button) each square turns blue, one by one. Only when all squares are blue, tapping the back-button once more will return to the previous screen. Also, if you click the "Open Dialog" button, the interceptors are disabled while the dialog is open.

  4. main_complex_example_test

    This package is test friendly, and this examples shows how to test the back button.

Testing

For testing purposes, the BackButtonInterceptor.popRoute() method may be called directly, to simulate pressing the back button. The list of all fired functions and their results is
recorded in the BackButtonInterceptor.results static variable.

Note: You may want to add BackButtonInterceptor.removeAll(); to your test's setUp function, so that you remove old interceptors between tests.

Debugging

In complex cases, to make it easier for you to debug your interceptors, you may print them to the console, with their names and z-indexes, by doing:

print(BackButtonInterceptor.describe());

See also:


The Flutter packages I've authored:

My Medium Articles:

My article in the official Flutter documentation:


Marcelo Glasberg:
https://github.com/marcglasberg
https://linkedin.com/in/marcglasberg/
https://twitter.com/glasbergmarcelo
https://stackoverflow.com/users/3411681/marcg
https://medium.com/@marcglasberg