Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial
  • Lezione 29 di 37
  • livello intermedio
Indice lezioni

Gestione della navigazione

In questa lezione vedremo come gestire la navigazione di un'app Flutter, imparando a gestire eventuali errori, e definendo transizioni personalizzate.
In questa lezione vedremo come gestire la navigazione di un'app Flutter, imparando a gestire eventuali errori, e definendo transizioni personalizzate.
Link copiato negli appunti

Nelle scorsa lezioni abbiamo mosso i primi passi nella definizione della navigazione e del routing di un applicazione Flutter utilizzando il Navigator e rotte nominali.

In questa lezione vedremo come:

  • impostare una rotta iniziale diversa da \;
  • gestione degli errori durante la navigazione;
  • utilizzo della proprietà onGenerateRoute e della classe PageRouteBuilder per la definizione di una transizione custom.

Impostare una rotta iniziale

Non necessariamente la home dell'applicazione deve essere rappresentata dalla rotta /. Infatti, la rotta che permette al framework di identificare la prima schermata può essere chiamata in un modo qualsiasi, come ad esempio /home. In questo caso, si dovrà impostare la proprietà MaterialApp.home alla schermata desiderata.

Vediamo un esempio.

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: HomePage(),
      routes: noSlashRouting(),
    );
  }
  Map<String, WidgetBuilder> noSlashRouting(){
    return {
      '/home': (context) => HomePageV2(),
      '/newpage': (context) => NewPageV2(),
    };
  }
}

Eseguendo l'applicazione, il risultato visivo e l'esperienza utente resteranno invariati rispetto ai risultati precedentemente ottenuti.

Un'altro aspetto interessante è la possibilità di utilizzare insieme alla proprietà route la proprietà intialRoute di MaterialApp, che permette di impostare una prima schermata differente da quella definita dalla rotta /.

Per complicare lo scenario, aggiungiamo una terza schermata che conterrà a sua volta un RaisedButton e impostiamo la proprietà onPressed del bottone in modo che punti alla HomePage.

class ThirdPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("ThirdPage"),
      ),
      body: Center(
        child: RaisedButton(
          onPressed: () {
            Navigator.pushNamed(context, '/');
          },
          child: Text('Go to HomePage!'),
        ),
      ),
    );
  }
}

A questo punto basterà aggiornare la classe MyApp come segue.

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      initialRoute: '/thirdpage',
      routes: threeRouting(),
  }
  Map<String, WidgetBuilder> threeRouting(){
    return {
      '/': (context) => HomePage(),
      '/newpage': (context) => NewPage(),
      '/thirdpage': (context) => ThirdPage(),
    };
  }
}

In questo codice d'esempio abbiamo aggiornato le rotte della nostra applicazione aggiungendo una nuova rotta relativa alla nuova schermata ThirdPage e abbiamo impostato la rotta iniziale dell'app proprio a questo elemento.

Eseguiamo quindi l'applicazione per ottenere il risultato desiderato.

Figura 168a. Esempio di utilizzo della proprietà initialRoute e di una navigazione a tre schermate per Android (click per ingrandire)Esempio di utilizzo della proprietà initialRoute e di una navigazione a tre schermate per Android
Figura 168b. Esempio di utilizzo della proprietà initialRoute e di una navigazione a tre schermate per iOS (click per ingrandire)Esempio di utilizzo della proprietà initialRoute e di una navigazione a tre schermate per iOS

Gestione degli errori di navigazione

Un'altra proprietà utile offerta dal widget MaterialApp è chiamata onUnknownRoute, che tramite una callback permette di gestire possibili errori durante la generazione di una rotta, fatta eccezione per la proprietà MaterialApp.initialRoute.

Generalmente, è consigliabile che questa callback generi una rotta che descriva una pagina di not found per comunicare all'utente che è avvenuto un errore.

Vediamo con un semplice esempio come usare questa proprietà.

Creiamo prima di tutto un nuovo widget che rappresenterà la schermata di not found e chiameremo NotFoundPage.

class NotFoundPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("PageNotFound"),
      ),
      body: Center(
        child: RaisedButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: Text('Go Back to HomePage!'),
        ),
      ),
    );
  }
}

Definita la classe, aggiorniamo la nostra MyApp al fine di integrare la proprietà MaterialApp.onUnknownRoute.

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      routes: mainRouting(),
      onUnknownRoute: (RouteSettings setting) {
        String unknownRoute = setting.name ;
        return new MaterialPageRoute(
            builder: (context) => NotFoundPage()
        );
      }
    );
  }
}

Modifichiamo infine la proprietà onPressed affinchè il metodo Navigator.pushNamed punti ad una rotta inesistente per generare un errore e mostrare la schermata NotFoundPage.

onPressed: () {
    Navigator.pushNamed(context, '/newp');
  },

Eseguiamo l'applicazione per vedere i risultati delle modifiche effettuate.

Figura 169a. Esempio di gestione degli errori nella generazione delle rotte per Android (click per ingrandire)Esempio di gestione degli errori nella generazione delle rotte per Android
Figura 169b. Esempio di gestione degli errori nella generazione delle rotte per iOS (click per ingrandire)Esempio di gestione degli errori nella generazione delle rotte per iOS

In questo caso, il framework non ha trovato una rotta col nome /new tra quelle disponibili e, invece di generare una schermata di errore, ha rimandato l'utente sulla pagina designata al fine di evidenziare un problema durante la navigazione.

Utilizzo della proprietà onGenerateRoute e della classe PageRouteBuilder

Vediamo infine come utilizzare la proprietà onGenerateRoute per definire rotte nominali e integrare nella nostra applicazione delle transizioni personalizzate tra le schermate.

Come anticipato all'inizio di questa lezione, la classe MaterialPageRoute definisce una rotta modale con una transizione dipendente dall'OS e per farlo estende la classe PageRoute. Analogamente, se vogliamo definire una nostra transizione diversa da quella dei default offerta dagli OS, dovremo creare un nuovo widget che estende la classe PageRouteBuilder (che estende PageRoute) e definire le proprietà:

  • pageBuilder per la creazione della pagina;
  • transitionsBuilder per la definizione della nostra transizione personalizzata.

Vediamo come farlo con un semplice esempio in cui l'obiettivo è creare una transizione che faccia entrare la nuova schermata da sinistra verso destra.

class SlideRightRoute extends PageRouteBuilder {
  final Widget widget;
  SlideRightRoute({this.widget})
      : super(
      pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
        return widget;
      },
      transitionsBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
        return new SlideTransition(
          position: new Tween<Offset>(
            begin: const Offset(-1.0, 0.0),
            end: Offset.zero,
          ).animate(animation),
          child: child,
        );
      }
  );
}

In particolare, tramite la proprietà pageBuilder definiamo il widget da mostrare, che viene passato come parametro del costruttore SlideRightRoute. Invece, con la proprietà transitionsBuilder, abbiamo definito a tutti gli effetti la nostra animazione personalizzata.

Definito il nostro nuovo PageRouteBuilder personalizzato non resta che modificare la classe MyApp per aggiungere la proprietà onGenerateRoute.

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      onGenerateRoute: (RouteSettings settings) {
        switch (settings.name) {
          case '/':
            return SlideRightRoute(widget: HomePage());
            break;
          case '/newpage':
            return SlideRightRoute(widget: NewPage());
            break;
          default:
            return SlideRightRoute(widget: NotFoundPage());
        }
      },
    );
  }

In questo caso abbiamo definito uno switch case in cui, dato il nome della rotta ottenuta dal RouteSettings, tramite la proprietà name restituiamo lo SlideRightRoute che prenderà in ingresso il widget da mostrare. Nel caso in cui il nome della rotta non fosse presente tra quelli definiti, lo switch case restituirà la rotta di default, che in questo caso è stata impostata a NotFoundPage ma può essere anche la HomePage della nostra app.

Eseguiamo quindi l'applicazione per vedere come si comporterà questa volta il framework durante la visualizzazione della nuova schermata.

Figura 170a. Esempio di definizione di una transizione personalizzata durante la navigazione per Android (click per ingrandire)Esempio di definizione di una transizione personalizzata durante la navigazione per Android
Figura 170b. Esempio di definizione di una transizione personalizzata durante la navigazione per iOS (click per ingrandire)Esempio di definizione di una transizione personalizzata durante la navigazione per iOS

Come si può notare, per entrambe le piattaforme è stata definita la medesima animazione per la transizione dalla HomePage alla NewPage.

È importante tenere a mente che, se decidiamo di utilizzare delle animazioni personalizzate per le transizioni tra schermate, queste andranno a sostituire del tutto e sempre le transazioni di default del sistema operativo (OS).

Il codice di questa lezione è disponibile su GitHub.

Ti consigliamo anche