• Stars
    star
    100
  • Rank 333,400 (Top 7 %)
  • Language
    Dart
  • License
    BSD 2-Clause "Sim...
  • Created over 5 years ago
  • Updated 7 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Flutter Package: May be used to intercept the Android back-button, as an alternative to `WillPopScope`.

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.


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

  • After you've finished you MUST remove each function by calling the remove() method. Alternatively, you may also provide a name when adding a function, and then later remove it by calling the removeByName(name) method.

  • If any of your interceptors throw an error, the error message will be printed to the console, but the error thrown will be a general error with not much information. You can change the treatment of errors by changing the static errorProcessing field.

  • Your functions can also process information about routes by using the function's RouteInfo info parameter. To get the current route in the navigator, call info.currentRoute(context). Also, info.routeWhenAdded contains the route that was the current one when the interceptor was added through the BackButtonInterceptor.add() method.

  • You can set up some function so that it only runs when the current route is the same route of when the interceptor was created. To that end, you can use info.ifRouteChanged() method:

    bool myInterceptor(bool stopDefaultButtonEvent, RouteInfo info) {    
      if (info.ifRouteChanged(context)) return false;
      ...
    }    
    

    This means the interceptor function is temporarily disabled while, for example, a dialog is open.

  • You can set up some function so that it only runs in certain routes:

    bool myInterceptor(bool stopDefaultButtonEvent, RouteInfo info) {    
      if (["myRoute1", "myRoute2", "myRoute3"]
         .contains(info.currentRoute(context))) return false;
      ...
    }    
    
  • Both info.routeWhenAdded and info.ifRouteChanged() only work if you passed the context parameter to the BackButtonInterceptor.add() method. Otherwise, info.routeWhenAdded will be null and info.ifRouteChanged() will thrown an error.

  • The current route can also be obtained by using the static method BackButtonInterceptor.getCurrentNavigatorRouteName(context).

  • The interceptor function can return bool or Future<bool>.

Import the package

Add back_button_interceptor as a dependency in your pubspec.yaml. Then, import it:

import 'package:back_button_interceptor/back_button_interceptor.dart';

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

More Repositories

1

i18n_extension

Flutter package: Easy and powerful internationalization using Dart extensions.
Dart
290
star
2

indexed_list_view

Flutter package: Similar to a ListView, but lets you programmatically jump to any item, by index.
Dart
248
star
3

async_redux

Flutter Package: A Redux version tailored for Flutter, which is easy to learn, to use, to test, and has no boilerplate. Allows for both sync and async reducers.
Dart
223
star
4

fast_immutable_collections

Dart Package: Immutable lists, sets, maps, and multimaps, which are as fast as their native mutable counterparts. Extension methods and comparators for native Dart collections.
Dart
188
star
5

assorted_layout_widgets

Flutter package: Assorted layout widgets that boldly go where no native Flutter widgets have gone before.
Dart
138
star
6

flutter_layout_article

Flutter Article: The Advanced Layout Rule Even Beginners Must Know
Dart
92
star
7

align_positioned

Flutter Package: When your desired layout or animation is too complex for Columns and Rows, this widget lets you position/size/rotate/transform its child in complex ways.
Dart
75
star
8

network_to_file_image

Flutter Package: This is a mixture of FileImage and NetworkImage. It will download the image from the url once, save it locally in the file system, and then use it from there in the future.
Dart
60
star
9

matrix4_transform

Flutter package: Helper math class for easily creating Matrix4 transformations, that you can use in Container's transform parameter and elsewhere.
Dart
52
star
10

animated_size_and_fade

Flutter Package: A widget that does a fade and size transition between widgets of same width but different heights, and you don't need to know their sizes in advance.
Dart
43
star
11

provider_for_redux

Flutter Package: Let's you use Provider with Redux.
Dart
24
star
12

themed

Flutter package: Define a theme (colors, text styles etc.) as static const values which can be changed dynamically. Also comes with useful extensions to create text styles by composition.
Dart
24
star
13

image_pixels

Flutter Package: Lets you extend the background color of an image, or else build any widget that depends on the image width/height, and the color of its pixels.
Dart
23
star
14

weak_map

Dart package: WeakMap is a map where the keys are weakly referenced. WeakContainer lets you check if an object is the same you had before. This package also contains cache functions for memoization done right, with weak-references.
Dart
20
star
15

bdd_framework

Dart package: BDD framework for Dart/Flutter. Lets you create BDD tests in code, and gives you easy to read error messages when assertions fail. Exports to Gherkin/Cucumber feature files.
Dart
12
star
16

redux_app_example

Complete Flutter app example, with AsyncRedux state management. Can also be used as a template to start a new project.
Dart
7
star
17

HibernateInspectionsPlugin

Initial Setup version 1.0
Java
3
star
18

marcelosdartplugin

Dart and Flutter plugin to add features to the IntelliJ IDE.
Java
3
star
19

SameAppDifferentTech

This project contains the SAME MOBILE APP implemented with DIFFERENT tech stacks: React Native, Flutter, Android, iOS.
TypeScript
2
star
20

bdd_framework_for_jest

BDD framework for Jest (JavaScript / TypeScript / React / React Native). Lets you create BDD tests in code, and gives you easy to read error messages when assertions fail. Exports to Gherkin/Cucumber feature files.
JavaScript
1
star
21

flutter_hooks_async_redux

Combines flutter_hooks and async_redux packages to add Redux to flutter_hooks.
Dart
1
star