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

Passare i dati ad una rotta

In questa lezione vedremo nel dettaglio tre diversi approcci per condividere dati durante la navigazione di un'app mobile realizzata con Flutter.
In questa lezione vedremo nel dettaglio tre diversi approcci per condividere dati durante la navigazione di un'app mobile realizzata con Flutter.
Link copiato negli appunti

Nelle lezioni precedenti, abbiamo analizzato in dettaglio i possibili approcci per navigare tra le schermate di un'applicazione così da permettere all'utente di scoprire le funzionalità disponibili e i dati forniti.

Come tutte le applicazioni moderne a cui siamo abituati, un aspetto utile è lo scambio di informazioni tra due schermate. La condivisione dei dati è, infatti, molto importante durante la navigazione dell'utente in quanto gli permette di interagire con nuove informazioni a partire dalle prime. Ad esempio, quando l'utente interagisce con una lista di elementi e clicca su uno di questi, l'informazione relativa all'identificativo univoco dell'elemento viene inoltrata alla schermata successiva per estrarre l'entità dal DB e popolare la schermata di dettaglio.

In questa e nella prossima lezione vedremo nel dettaglio tre diversi approcci per condividere dati durante la navigazione attraverso esempi pratici ed intuitivi.

Scambio dati tra due schermate tramite MaterialRoutePage

Vediamo alcuni esempi pratici per lo scambio dati tra due schermate di un'applicazione contestualmente alla navigazione, sfruttando proprio i componenti Route, Navigator e MaterialRoutePage con cui abbiamo familiarizzato nella lezione precedente.

Come di consueto, creiamo un nuovo progetto come illustrato nella lezione 6 di questa guida e cancelliamo tutto eccetto la classe MyApp, definita come segue.

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: /*set home*/,
  }
}

Prima di proseguire con gli esempi, definiamo una classe di oggetti che utilizzeremo come dato da passare tra due schermate. In particolare, andremo a definire la classe Article che rappresenta un articolo composto da due proprietà:

  • un titolo;
  • una descrizione.

Per farlo basterà definire la classe come segue.

class Article {
  final String title;
  final String description;
  Article(this.title, this.description);
}

In particolare, abbiamo definito all'interno della classe un costruttore che accetta come parametri di ingresso il titolo e la descrizione.

Per semplicità abbiamo messo questa classe all'interno del file main.dart, ma è opportuno definire il modello di dominio all'interno di un apposito file .dart contenente le entità che rappresentano il dominio della nostra applicazione. L'organizzazione del codice sarà oggetto delle prossime lezioni.

Definiamo adesso due schermate:

  • una che chiameremo HomePage, che mostrerà un semplice bottone e inoltrerà i dati alla seconda schermata;
  • una schermata di dettaglio, ArticleDetailPage, che mostrerà le informazioni (titolo e descrizione) dell'articolo selezionato dall'utente.

Vediamo come definire le due classi e partiamo dalla HomePage.

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Home'),
      ),
      body: Center(
        child: RaisedButton(
          onPressed: () {ì
          },
          child: Text('Open ArticleDetailPage'),
        ),
      ),
    );
  }
}

In questo modo, abbiamo creato un nuovo StatelessWidget composto da:

  • uno Scaffold;
  • un AppBar;
  • un RaisedButton posto al centro della schermata.

Quando l'utente cliccherà sul bottone, aprirà la pagina di dettaglio che può essere definita così.

class ArticleDetailPage extends StatelessWidget {
  final Article article;
  ArticleDetailPage({Key key, this.article}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(article.title),
      ),
      body: Padding(
        padding: EdgeInsets.all(16.0),
        child: Text(article.description),
      ),
    );
  }
}

In particolare abbiamo:

  • definito la proprietà article di tipo Article;
  • definito il costruttore per la classe ArticleDetailPage che può prendere in input un oggetto di tipo Article;
  • sovrascritto il metodo build affinché il titolo dell'AppBar sia impostato alla proprietà title definita nell'oggetto article, ed è stato definito un widget Text contenente la descrizione dell'articolo.

Non resta che definire la callback per la proprietà RaisedButton.onPressed della HomePage che:

  • definirà un nuovo oggetto Article composto da un titolo e una descrizione;
  • definirà un nuovo widget Route usando il MaterialPageRoute widget visto nella precedente lezione;
  • invocherà il metodo Navigator.push per comunicare al framework di navigare verso la nuova rotta.

Riportiamo di seguito una possibile implementazione della callback così definita.

onPressed: () {
    Article article =
        new Article('Article', 'This is a simple text for Article');
    Route route = MaterialPageRoute(
      builder: (context) => ArticleDetailPage(article: article),
    );
    Navigator.push(context, route);
  },

Impostiamo la proprietà MaterialApp.home della classe MyApp alla classe HomePage

home: HomePage(),

ed eseguiamo l'applicazione per vedere i risultati delle nostre modifiche.

Figura 171a. Esempio base di scambio dati tra due schermate per Android (click per ingrandire)Esempio base di scambio dati tra due schermate per Android
Figura 171b. Esempio base di scambio dati tra due schermate per iOS (click per ingrandire)Esempio base di scambio dati tra due schermate per iOS

Come si vede in figura, cliccando sul bottone presente nella prima schermata, l'utente crea un nuovo Article e inoltra l'oggetto alla rotta che sostituisce la schermata della HomePage con la rotta modale contenente il widget ArticleDetailPage, che mostra i dettagli dell'articolo.

Complichiamo leggermente lo scenario e immaginiamo di avere una lista di articoli da visualizzare e da cui possiamo sceglierne uno per visualizzare un dettaglio.

Per farlo, dovremo creare nella nostra app una nuova schermata in cui visualizzare una lista predefinita e popolata staticamente. Vediamo come con il seguente esempio.

ArticleListPage({Key key, @required this.articles}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Todos'),
      ),
      body: ListView.builder(
        itemCount: articles.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text(articles[index].title),
            onTap: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) =>
                      ArticleDetailPage(article: articles[index]),
                ),
              );
            },
          );
        },
      ),
    );
  }
}

In questo caso abbiamo definito:

  • un nuovo widget, ArticleListPage, avente la proprietà articles che definisce una lista di oggetti Article da mostrare all'utente;
  • definito il costruttore della classe che prende come input (obbligatorio) una lista di articoli;
  • all'interno del metodo ArticleListPage.build uno Scaffold contenente l'AppBar e come body una nuova ListView costruita a partire dalla proprietà articles.

Abbiamo inoltre definito la proprietà ListTile.onTap (di cui abbiamo discusso nella lezione 18) in modo che, cliccando su un elemento della lista, la callback invochi il metodo Navigator.push per rimandare l'utente alla pagina di dettaglio con le nuove informazioni passate al costruttore del widget ArticleDetailPage.

Adesso non resta che creare la nostra lista statica e modificare la classe MyApp come segue.

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      // . . .
      home: ArticleListPage(
        articles: List.generate(
          20,
              (i) =>
              Article(
                'Article $i',
                'This is a simple text for Article $i',
              ),
        ),
      ),
    );
  }
}

In questo caso abbiamo impostato la proprietà home con la classe ArticleListPage e assegnato alla proprietà ArticleListPage.articles una lista generata dinamicamente tramite il metodo List.generate, che crea una lista di 20 articoli composti da un titolo e una descrizione.

Non resta che eseguire l'applicazione per vedere i risultati delle modifiche effettuate.

Figura 172a. Esempio di navigazione con scambio di dati tra una schermata di listing e una di dettaglio per Android (click per ingrandire)Esempio di navigazione con scambio di dati tra una schermata di listing e una di dettaglio per Android
Figura 172b. Esempio di navigazione con scambio di dati tra una schermata di listing e una di dettaglio per iOS (click per ingrandire)Esempio di navigazione con scambio di dati tra una schermata di listing e una di dettaglio per iOS

Come si può notare, quando l'utente tocca uno specifico elemento della lista, la callback della proprietà onTap viene invocata dal framework per ridirezionare l'utente alla pagina di dettaglio tramite il Navigator. Una volta atterrato sulla pagina di dettaglio l'utente vede il titolo e la descrizione dell'articolo selezionato.

Questo semplice esempio non ne fa uso, ma è possibile estendere quanto fatto alle rotte nominali.

Il codice di questa lezione è disponibile su GitHub.

Ti consigliamo anche