Saturday, August 3, 2024
HomeiOS Developmentios - Flutter: Mechanically Show a Again Button within the AppBar...

ios – Flutter: Mechanically Show a Again Button within the AppBar Primarily based on the Nested Navigation Stack?


I am engaged on a Flutter app the place I am utilizing GoRouter for navigation with a backside navigation bar to change between completely different sections. Every part has its personal nested navigation stack.

I wish to mechanically show a again button within the AppBar when the person will not be on the foundation route of a piece. Nonetheless, my present implementation will not be working as anticipated. Particularly, the next line doesn’t appropriately decide if there’s a path to pop within the nested navigation stack:

closing canPop = navigatorKey.currentState?.canPop() ?? false;

Here’s a simplified model of my code:
app.dart

import 'package deal:firebase_ui_auth/firebase_ui_auth.dart';
import 'package deal:flutter/materials.dart';
import 'package deal:go_router/go_router.dart';
import 'package deal:flutter_riverpod/flutter_riverpod.dart';
import 'package deal:hanazono_app/src/authentication/auth_gate.dart';
import 'package deal:hanazono_app/views/collection_screen.dart';
import 'package deal:hanazono_app/views/conversation_screen.dart';
import 'package deal:hanazono_app/views/home_screen.dart';
import 'package deal:hanazono_app/views/new_specimen_screen.dart';
import 'package deal:hanazono_app/views/scaffold_with_navbar.dart';

closing GlobalKey<NavigatorState> _rootNavigatorKey =
    GlobalKey<NavigatorState>(debugLabel: 'root');
closing GlobalKey<NavigatorState> _homeNavigatorKey =
    GlobalKey<NavigatorState>(debugLabel: 'house');
closing GlobalKey<NavigatorState> _collectionNavigatorKey =
    GlobalKey<NavigatorState>(debugLabel: 'assortment');
closing GlobalKey<NavigatorState> _newSpecimenNavigatorKey =
    GlobalKey<NavigatorState>(debugLabel: 'newSpecimen');
closing GlobalKey<NavigatorState> _conversationNavigatorKey =
    GlobalKey<NavigatorState>(debugLabel: 'dialog');

class MyApp extends ConsumerStatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends ConsumerState<MyApp> {
  late closing GoRouter _router;

  @override
  void initState() {
    tremendous.initState();
    _router = GoRouter(
      navigatorKey: _rootNavigatorKey,
      initialLocation: "https://stackoverflow.com/",
      routes: [
        StatefulShellRoute.indexedStack(
          parentNavigatorKey: _rootNavigatorKey,
          builder: (BuildContext context, GoRouterState state,
              StatefulNavigationShell navigationShell) {
            return ScaffoldWithNavBar(navigationShell: navigationShell);
          },
          branches: [
            StatefulShellBranch(
              navigatorKey: _homeNavigatorKey,
              routes: [
                GoRoute(
                  path: "https://stackoverflow.com/",
                  builder: (context, state) => HomeScreen(),
                ),
              ],
            ),
            StatefulShellBranch(
              navigatorKey: _collectionNavigatorKey,
              routes: [
                GoRoute(
                    path: '/collection',
                    parentNavigatorKey: _collectionNavigatorKey,
                    builder: (context, state) => const CollectionScreen(),
                    routes: [
                      GoRoute(
                        path: 'newSpecimen',
                        builder: (context, state) => const NewSpecimenScreen(),
                      ),
                    ]),
              ],
            ),
            StatefulShellBranch(
              navigatorKey: _newSpecimenNavigatorKey,
              routes: [
                GoRoute(
                  path: '/newSpecimen0',
                  builder: (context, state) => const NewSpecimenScreen(),
                ),
              ],
            ),
            StatefulShellBranch(
              navigatorKey: _conversationNavigatorKey,
              routes: [
                GoRoute(
                  path: '/conversation',
                  builder: (context, state) {
                    final modelId = state.uri.queryParameters['modelId'] ??
                        'exampleModelId';
                    closing modelType =
                        state.uri.queryParameters['modelType'] ?? 'Taxon';
                    return ConversationScreen(
                        modelId: modelId, modelType: modelType);
                  },
                ),
              ],
            ),
          ],
        ),
        GoRoute(
          path: '/auth',
          builder: (context, state) => const AuthGate(),
        ),
        GoRoute(
          path: '/profile',
          builder: (context, state) => const ProfileScreen(),
        ),
      ],
    );
  }

  @override
  Widget construct(BuildContext context) {
    return MaterialApp.router(
      routerConfig: _router,
    );
  }
}

scaffold_with_navbar.dart

import 'package deal:flutter/materials.dart';
import 'package deal:go_router/go_router.dart';
import 'package deal:logging/logging.dart';
import 'package deal:flutter_riverpod/flutter_riverpod.dart';
import '../suppliers.dart';

class ScaffoldWithNavBar extends ConsumerWidget {
  closing StatefulNavigationShell navigationShell;

  const ScaffoldWithNavBar({
    required this.navigationShell,
    Key? key,
  }) : tremendous(key: key ?? const ValueKey<String>('ScaffoldWithNavBar'));

  @override
  Widget construct(BuildContext context, WidgetRef ref) {
    closing GoRouter router = GoRouter.of(context);
    closing currentLocation = router.routerDelegate.currentConfiguration.fullPath;
    Logger.root.information('Present path: $currentLocation');

    int currentIndex = navigationShell.currentIndex;
    Logger.root.information('Present index: $currentIndex');

    closing person = ref.watch(authProvider).maybeWhen(
          knowledge: (person) => person,
          orElse: () => null,
        );

    closing navigatorKey = navigationShell.route.branches[currentIndex].navigatorKey;
    closing canPop = navigatorKey.currentState?.canPop() ?? false;
    Logger.root.information('Ought to show again button: $canPop');

    // Log the state of the present tab's navigation stack
    if (navigatorKey.currentState != null) {
      Logger.root.information(
          'Present tab's navigation stack: ${navigatorKey.currentState!.widget.toString()}');
    }

    return Scaffold(
      appBar: AppBar(
        main: canPop
            ? IconButton(
                icon: Icon(Icons.arrow_back),
                onPressed: () {
                  Logger.root.information('Again button pressed');
                  navigatorKey.currentState?.pop();
                },
              )
            : null,
        title: const Textual content('My App'),
        actions: [
          if (user != null && !user.isAnonymous)
            IconButton(
              icon: Icon(Icons.person),
              onPressed: () {
                context.go('/profile');
              },
            )
          else
            TextButton(
              onPressed: () {
                context.go('/auth');
              },
              child: Text('Login'),
            ),
        ],
      ),
      physique: navigationShell,
      bottomNavigationBar: NavigationBar(
        backgroundColor: Colours.white,
        selectedIndex: currentIndex,
        locations: const [
          NavigationDestination(
            icon: Icon(Icons.home),
            label: 'Home',
          ),
          NavigationDestination(
            icon: Icon(Icons.local_florist),
            label: 'Collection',
          ),
          NavigationDestination(
            icon: Icon(Icons.add),
            label: 'New Specimen',
          ),
          NavigationDestination(
            icon: Icon(Icons.chat),
            label: 'Conversation',
          ),
        ],
        onDestinationSelected: (index) {
          Logger.root.information('Backside navigation merchandise tapped: $index');
          navigationShell.goBranch(
            index,
            initialLocation: index == navigationShell.currentIndex,
          );
        },
      ),
    );
  }
}

Assortment Display

import 'package deal:flutter/materials.dart';
import 'package deal:go_router/go_router.dart';
import 'package deal:flutter_riverpod/flutter_riverpod.dart';
import '../suppliers.dart';

class CollectionScreen extends ConsumerWidget {
  const CollectionScreen({tremendous.key});

  @override
  Widget construct(BuildContext context, WidgetRef ref) {
    closing currentTabIndex = ref.watch(currentTabProvider);
    closing navigatorKey =
        ref.learn(navigationShellProvider.notifier).state[currentTabIndex];

    return Scaffold(
      physique: Heart(
        youngster: Textual content(
          'That is the gathering display',
          fashion: Theme.of(context).textTheme.headlineLarge,
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          context.push('/assortment/newSpecimen');
        },
        youngster: Icon(Icons.add),
      ),
    );
  }
}

Problem:
When navigating inside a tab, the currentLocation solely reveals the bottom path of the tab, not the particular nested route (e.g., /assortment as a substitute of /assortment/newSpecimen). Consequently, the again button logic doesn’t work appropriately.

Objective:
Correctly handle the nested navigation stack for every tab in order that the again button is displayed when not on the foundation route of the tab.

Query:
How can I appropriately test the nested navigation stack for every tab to find out if the again button must be displayed?

Thanks on your assist!



Supply hyperlink

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments