Navigazione tra schermate in Flutter con go_router
GuideIntermedio35 min Flutter 3.x

Navigazione tra schermate in Flutter con go_router

La navigazione è uno degli aspetti fondamentali di ogni applicazione mobile. Flutter offre il Navigator integrato, ma quando l'app cresce gestire le rotte in modo imperativo diventa complicato.

In questo tutorial useremo go_router, il pacchetto ufficiale supportato dal team Flutter, che permette una navigazione dichiarativa basata su URL. Vedremo come definire le rotte, passare parametri, gestire i redirect (utili per l'autenticazione) e configurare una pagina di errore.

Al termine avrai una struttura di navigazione pulita e pronta per scalare.

  1. 1

    Aggiungere la dipendenza go_router

    Per prima cosa aggiungiamo il pacchetto go_router al nostro progetto. Apri il file pubspec.yaml e inserisci la dipendenza nella sezione dependencies.

    In alternativa puoi eseguire il comando da terminale:

    flutter pub add go_router
    

    Dopo l'aggiunta esegui flutter pub get per scaricare il pacchetto.

    dependencies:
      flutter:
        sdk: flutter
      go_router: ^14.0.0

    Risultato atteso

    Il pacchetto go_router è installato e disponibile per l'import nel progetto.

  2. 2

    Creare le schermate di base

    Creiamo due semplici schermate che useremo per la navigazione: una HomeScreen e una DetailsScreen. La schermata dei dettagli accetterà un parametro id che mostreremo a video.

    Queste sono normali StatelessWidget di Flutter.

    import 'package:flutter/material.dart';
    import 'package:go_router/go_router.dart';
    
    class HomeScreen extends StatelessWidget {
      const HomeScreen({super.key});
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(title: const Text('Home')),
          body: Center(
            child: ElevatedButton(
              onPressed: () => context.go('/details/42'),
              child: const Text('Vai ai dettagli'),
            ),
          ),
        );
      }
    }
    
    class DetailsScreen extends StatelessWidget {
      final String id;
      const DetailsScreen({super.key, required this.id});
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(title: const Text('Dettagli')),
          body: Center(child: Text('Elemento con id: $id')),
        );
      }
    }

    Risultato atteso

    Hai due widget pronti: HomeScreen con un bottone e DetailsScreen che riceve un id.

  3. 3

    Configurare il GoRouter

    Definiamo ora la configurazione delle rotte. Creiamo un'istanza di GoRouter con la lista delle GoRoute.

    Nota l'uso di :id nel path: è un parametro dinamico che recuperiamo tramite state.pathParameters.

    final GoRouter router = GoRouter(
      initialLocation: '/',
      routes: [
        GoRoute(
          path: '/',
          builder: (context, state) => const HomeScreen(),
        ),
        GoRoute(
          path: '/details/:id',
          builder: (context, state) {
            final id = state.pathParameters['id']!;
            return DetailsScreen(id: id);
          },
        ),
      ],
    );

    Risultato atteso

    Hai un oggetto router con due rotte: la home e i dettagli con parametro id.

  4. 4

    Collegare il router all'app

    Per attivare go_router dobbiamo usare il costruttore MaterialApp.router al posto del classico MaterialApp, passando la configurazione tramite routerConfig.

    import 'package:flutter/material.dart';
    import 'package:go_router/go_router.dart';
    
    void main() => runApp(const MyApp());
    
    class MyApp extends StatelessWidget {
      const MyApp({super.key});
    
      @override
      Widget build(BuildContext context) {
        return MaterialApp.router(
          title: 'Demo go_router',
          routerConfig: router,
        );
      }
    }

    Risultato atteso

    Avviando l'app vedi la HomeScreen; toccando il bottone navighi a /details/42.

  5. 5

    Aggiungere named routes e parametri query

    Usare i path completi nel codice è poco manutenibile. go_router permette di assegnare un nome alle rotte e navigare con goNamed. Possiamo anche passare parametri query.

    Aggiorniamo la rotta dei dettagli con un nome e leggiamo un eventuale parametro query from.

    GoRoute(
      path: '/details/:id',
      name: 'details',
      builder: (context, state) {
        final id = state.pathParameters['id']!;
        final from = state.uri.queryParameters['from'] ?? 'sconosciuto';
        return DetailsScreen(id: id, from: from);
      },
    ),
    
    // Navigazione con nome e parametri:
    context.goNamed(
      'details',
      pathParameters: {'id': '42'},
      queryParameters: {'from': 'home'},
    );

    Risultato atteso

    Puoi navigare usando il nome della rotta e leggere i parametri query come 'from'.

  6. 6

    Gestire i redirect per l'autenticazione

    Una funzionalità potente di go_router è il redirect, eseguito prima di mostrare una rotta. È perfetto per proteggere pagine riservate agli utenti autenticati.

    Se l'utente non è loggato e tenta di accedere a una rotta protetta, lo reindirizziamo alla pagina di login.

    bool isLoggedIn = false;
    
    final router = GoRouter(
      initialLocation: '/',
      redirect: (context, state) {
        final goingToProfile = state.matchedLocation == '/profile';
        if (goingToProfile && !isLoggedIn) {
          return '/login';
        }
        return null; // nessun redirect
      },
      routes: [
        GoRoute(path: '/', builder: (c, s) => const HomeScreen()),
        GoRoute(path: '/login', builder: (c, s) => const LoginScreen()),
        GoRoute(path: '/profile', builder: (c, s) => const ProfileScreen()),
      ],
    );

    Risultato atteso

    Tentando di aprire /profile senza login, vieni reindirizzato a /login.

  7. 7

    Aggiungere una pagina di errore personalizzata

    Infine, gestiamo le rotte non valide con errorBuilder. Quando l'utente naviga verso un URL inesistente, mostriamo una schermata di errore amichevole con un pulsante per tornare alla home.

    final router = GoRouter(
      initialLocation: '/',
      errorBuilder: (context, state) => Scaffold(
        appBar: AppBar(title: const Text('Errore')),
        body: Center(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              Text('Pagina non trovata: ${state.uri}'),
              const SizedBox(height: 16),
              ElevatedButton(
                onPressed: () => context.go('/'),
                child: const Text('Torna alla Home'),
              ),
            ],
          ),
        ),
      ),
      routes: [
        GoRoute(path: '/', builder: (c, s) => const HomeScreen()),
      ],
    );

    Risultato atteso

    Navigando verso una rotta inesistente vedi la pagina di errore con il pulsante per tornare alla home.

CondividiXLinkedInFacebookWhatsApp

Commenti (0)

Ancora nessun commento. Inizia tu!