Skip to content

Software Development at Program Tom LTD

Place for coding, programming, development and software in general.

Menu
  • Blog
  • PDF Booklets
  • Dev Utils & Content
  • Java Spring Boot Or Web Apps
  • English
    • български
    • English
    • Español
    • Português
    • हिन्दी
    • Русский
    • Deutsch
    • Français
    • Italiano
    • العربية
  • About Us
  • Flutter Apps
Menu
Flutter Back Button Navigation Handling

Flutter Back Button Navigation Handling

Posted on April 27, 2025May 10, 2025 by Toma Velev

Imagine the scenario in a Flutter app with go_router for navigation, a bottom navigation bar (say, Home, Search, Profile, etc.) and you want to handle Back button behavior smartly:

    1. If you are on another tab (e.g., Search, Profile), pressing back should switch back to the initial tab (e.g., Home).
    2. If you are already on the initial tab (Home) but a search/filter is active, pressing back should clear the search first.
    3. Only when on Home and search is cleared, pressing back should exit the app.

Here’s the general strategy you can use:

  • Wrap your whole Scaffold in a WillPopScope widget.
  • Inside onWillPop, implement the logic:
    • If not on the initial tab → set tab to initial, return false (don’t pop).
    • If on the initial tab but search is active → clear search, return false.
    • If on the initial tab and search is clear → return true to allow app exit.

Example Code Structure:

class MainScreen extends StatefulWidget {
  @override
  State<MainScreen> createState() => _MainScreenState();
}

class _MainScreenState extends State<MainScreen> {
  int _currentIndex = 0; // Track bottom navigation
  bool _isSearchActive = false; // Track search state

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async {
        if (_currentIndex != 0) {
          setState(() {
            _currentIndex = 0; // Go back to initial tab
          });
          return false; // Don't exit app
        } else if (_isSearchActive) {
          setState(() {
            _isSearchActive = false; // Clear search
          });
          return false; // Don't exit app
        }
        return true; // Allow app to exit
      },
      child: Scaffold(
        body: _buildPage(), // build page based on _currentIndex
        bottomNavigationBar: BottomNavigationBar(
          currentIndex: _currentIndex,
          onTap: (index) {
            setState(() {
              _currentIndex = index;
            });
            // Also, navigate with go_router if needed
          },
          items: [
            BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Home'),
            BottomNavigationBarItem(icon: Icon(Icons.search), label: 'Search'),
            BottomNavigationBarItem(icon: Icon(Icons.person), label: 'Profile'),
          ],
        ),
      ),
    );
  }

  Widget _buildPage() {
    switch (_currentIndex) {
      case 0:
        return HomePage(
          onSearchStateChanged: (bool isSearching) {
            _isSearchActive = isSearching;
          },
        );
      case 1:
        return SearchPage();
      case 2:
        return ProfilePage();
      default:
        return Container();
    }
  }
}

Important notes:

  • onSearchStateChanged can be called from your HomePage when the search bar is active/inactive.
  • If you’re using go_router, you might have to sync _currentIndex with the current location path.
  • Also for tabbed navigation, you might want to look into ShellRoute in go_router for more advanced setups.

Quick behavior summary:

Situation What happens when pressing back
On Search tab Moves back to Home tab
On Home tab with active search Clears the search
On Home tab, search cleared Exits the app

📚 How WillPopScope executes when multiple are in the widget tree:

  • Closest to the focused route (deepest in the tree) gets called first.
  • It bubbles up from the innermost WillPopScope to the outer ones, one by one.
  • If any onWillPop returns false, the pop is cancelled immediately — no further WillPopScope will be called.
  • If onWillPop returns true, the next outer WillPopScope (if any) is called.

✅ First one to return false wins → pop canceled.
✅ All must return true for pop to succeed → then the Navigator pops the route.


🔥 Quick mental model:

Imagine WillPopScopes stacked like this:

App
 └── Navigator
      └── WillPopScope A // In a Root View
            └── WillPopScope B - In a Screen View
                  └── WillPopScope C - In a Sub-Screen View
                        └── Some Very Inner View

➡️ Press Back →
First WillPopScope C‘s onWillPop is called.

  • If C returns true, then WillPopScope B is called.
  • If B returns true, then WillPopScope A is called.
  • If A returns true, finally the pop happens.

If any of them returns false, the pop stops immediately.


🛠 Practical example:

WillPopScope(
  onWillPop: () async {
    print('Outer Scope');
    return true;
  },
  child: WillPopScope(
    onWillPop: () async {
      print('Inner Scope');
      return true;
    },
    child: Scaffold(
      appBar: AppBar(title: Text('Nested WillPopScope')),
    ),
  ),
);

👉 Press Back:

  • Prints Inner Scope
  • Then prints Outer Scope
  • Then pop happens.

If Inner Scope returns false, you will never see Outer Scope being printed.

  • Example of GridView Builder in Flutter
  • How to Visualize Listview inside Listview in Flutter
  • What other usages you know about public private cryptography
  • Get a Flutter App to Production
  • Firebase Dynamic Links Deprecation – migrating out to Java

Categories

  • Apps (20)
  • ChatGPT (19)
  • Choosing a Framework (38)
  • Flutter (201)
  • Graphical User Interface (13)
  • Marketing (113)
  • Software Development (268)
  • Spring (41)
  • StartUp (21)
  • Uncategorized (15)
  • Uncategorized (4)
  • Vaadin (14)

Tags

Algorithms (9) crypto (29) flutterdev (39) General (86) Java (7) QR & Bar Codes (3) Software Dev Choices (33) Spring Boot (1) standards (1) Theme (3) User Authentication & Authorization (9) User Experience (10) Utilities (19) WordPress (11)

Product categories

  • All Technologies (83)
    • Flutter Apps (23)
    • GPT (4)
    • Java (38)
    • Native Android (3)
    • PHP (9)
    • Spring (Boot) / Quarkus (35)
    • Utils (15)
    • Vaadin 24+ (27)
    • Vaadin 8 (1)
  • Apps (18)
    • Employees DB (1)
    • Notes (6)
    • Personal Budget (1)
    • Recipes Book (1)
    • Stuff Organizer (1)
    • To-Do (2)
  • PDF Books (3)
  • Source Code Generators (8)

Recent Posts

  • Example of GridView Builder in Flutter
  • How to Visualize Listview inside Listview in Flutter
  • What other usages you know about public private cryptography
  • Get a Flutter App to Production
  • Firebase Dynamic Links Deprecation – migrating out to Java

Post Categories

  • Apps (20)
  • ChatGPT (19)
  • Choosing a Framework (38)
  • Flutter (201)
  • Graphical User Interface (13)
  • Marketing (113)
  • Software Development (268)
  • Spring (41)
  • StartUp (21)
  • Uncategorized (15)
  • Uncategorized (4)
  • Vaadin (14)