MDC-102 Flutter: struttura e layout del materiale

1. Introduzione

logo_components_color_2x_web_96dp.png

I componenti Material (MDC) aiutano gli sviluppatori a implementare Material Design. Creato da un team di ingegneri e progettisti UX di Google, MDC include decine di componenti UI belli e funzionali ed è disponibile per Android, iOS, web e Flutter.material.io/develop

Nel codelab MDC-101, hai utilizzato due componenti Material per creare una pagina di accesso: campi di testo e pulsanti con increspature di inchiostro. Ora ampliamo questa base aggiungendo navigazione, struttura e dati.

Cosa creerai

In questo codelab creerai una schermata Home per un'app chiamata Shrine, un'app di e-commerce che vende abbigliamento e prodotti per la casa. Contiene:

  • Una barra dell'app in alto
  • Un elenco a griglia pieno di prodotti

Android

iOS

App di e-commerce con una barra dell'app in alto e una griglia piena di prodotti

App di e-commerce con una barra dell'app in alto e una griglia piena di prodotti

Componenti e sottosistemi Material Flutter in questo codelab

  • Barra dell'app in alto
  • Griglie
  • Carte

Come valuteresti il tuo livello di esperienza con lo sviluppo Flutter?

Principiante Intermedio Avanzato

2. Configura l'ambiente di sviluppo Flutter

Per completare questo lab, hai bisogno di due software: l'SDK Flutter e un editor.

Puoi eseguire il codelab utilizzando uno qualsiasi di questi dispositivi:

  • Un dispositivo fisico Android o iOS connesso al computer e impostato sulla modalità sviluppatore.
  • Il simulatore iOS (richiede l'installazione degli strumenti Xcode).
  • L'emulatore Android (richiede la configurazione in Android Studio).
  • Un browser (Chrome è necessario per il debug).
  • Come applicazione desktop Windows, Linux o macOS. Devi sviluppare sulla piattaforma in cui prevedi di eseguire il deployment. Pertanto, se vuoi sviluppare un'app desktop Windows, devi svilupparla su Windows per accedere alla catena di build appropriata. Esistono requisiti specifici del sistema operativo trattati in dettaglio su docs.flutter.dev/desktop.

3. Scarica l'app iniziale del codelab

Hai seguito il corso MDC-101?

Se hai completato MDC-101, il codice dovrebbe essere pronto per questo codelab. Vai al passaggio: Aggiungere una barra delle app superiore.

Partire da zero?

Scaricare l'app codelab iniziale

L'app iniziale si trova nella directory material-components-flutter-codelabs-102-starter_and_101-complete/mdc_100_series.

...o clonalo da GitHub

Per clonare questo codelab da GitHub, esegui i seguenti comandi:

git clone https://github.com/material-components/material-components-flutter-codelabs.git
cd material-components-flutter-codelabs/mdc_100_series
git checkout 102-starter_and_101-complete

Apri il progetto ed esegui l'app

  1. Apri il progetto nell'editor che preferisci.
  2. Segui le istruzioni per "Eseguire l'app" nella sezione Guida rapida: prova per l'editor che hai scelto.

Operazione riuscita. Sul dispositivo dovrebbe essere visualizzata la pagina di accesso di Shrine del codelab MDC-101.

Android

iOS

pagina di accesso con i campi per nome utente e password, i pulsanti Annulla e Avanti

pagina di accesso con i campi nome utente e password, i pulsanti Annulla e Avanti

Ora che la schermata di accesso ha un bell'aspetto, inseriamo alcuni prodotti nell'app.

4. Aggiungere una barra dell'app in alto

Se fai clic sul pulsante "Avanti", vedrai la schermata Home con il messaggio "Ce l'hai fatta!". Fantastico. Ma ora l'utente non ha azioni da intraprendere o non sa dove si trova nell'app. Per aiutarlo, è il momento di aggiungere la navigazione.

Material Design offre pattern di navigazione che garantiscono un elevato grado di usabilità. Uno dei componenti più visibili è la barra dell'app in alto.

Per fornire la navigazione e consentire agli utenti di accedere rapidamente ad altre azioni, aggiungiamo una barra delle app nella parte superiore.

Aggiungere un widget AppBar

In home.dart, aggiungi una barra delle app allo Scaffold e rimuovi const evidenziato:

return const Scaffold(
  // TODO: Add app bar (102)
  appBar: AppBar(
    // TODO: Add buttons and title (102)
  ),

L'aggiunta di AppBar al campo appBar: di Scaffold ci offre un layout perfetto e senza costi, mantenendo la barra delle app nella parte superiore della pagina e il corpo sotto.

Aggiungere un widget di testo

In home.dart, aggiungi un titolo alla barra delle app:

// TODO: Add app bar (102)
  appBar: AppBar(
    // TODO: Add buttons and title (102)
    title: const Text('SHRINE'),
    // TODO: Add trailing buttons (102)

Salvare il progetto.

Android

iOS

una barra delle app con Shrine come titolo

una barra delle app con Shrine come titolo

Molte barre delle app hanno un pulsante accanto al titolo. Aggiungiamo un'icona del menu nella nostra app.

Aggiungere un IconButton iniziale

Mentre ti trovi ancora in home.dart, imposta un IconButton per il campo leading: di AppBar. (inseriscilo prima del campo title: per imitare l'ordine da sinistra a destra):

    // TODO: Add buttons and title (102)
    leading: IconButton(
      icon: const Icon(
        Icons.menu,
        semanticLabel: 'menu',
      ),
      onPressed: () {
        print('Menu button');
      },
    ),

Salvare il progetto.

Android

iOS

una barra delle app con Santuario come titolo e un'icona del menu di navigazione

una barra delle app con Santuario come titolo e un'icona del menu di navigazione

L'icona del menu (nota anche come"hamburger") viene visualizzata esattamente dove ti aspetteresti.

Puoi anche aggiungere pulsanti al lato finale del titolo. In Flutter, queste sono chiamate "azioni".

Aggiungere azioni

C'è spazio per altri due IconButtons.

Aggiungili all'istanza AppBar dopo il titolo:

// TODO: Add trailing buttons (102)
actions: <Widget>[
  IconButton(
    icon: const Icon(
      Icons.search,
      semanticLabel: 'search',
    ),
    onPressed: () {
      print('Search button');
    },
  ),
  IconButton(
    icon: const Icon(
      Icons.tune,
      semanticLabel: 'filter',
    ),
    onPressed: () {
      print('Filter button');
    },
  ),
],

Salvare il progetto. La schermata Home dovrebbe essere simile a questa:

Android

iOS

una barra delle app con Shrine come titolo e un&#39;icona del menu hamburger, nonché icone di ricerca e personalizzazione finali

una barra delle app con Shrine come titolo e un&#39;icona del menu hamburger, nonché icone di ricerca e personalizzazione finali

Ora l'app ha un pulsante principale, un titolo e due azioni sul lato destro. La barra delle app mostra anche l'elevazione utilizzando un'ombra leggera che indica che si trova su un livello diverso rispetto ai contenuti.

5. Aggiungere una scheda in una griglia

Ora che la nostra app ha una struttura, organizziamo i contenuti inserendoli in schede.

Aggiungere una GridView

Iniziamo aggiungendo una scheda sotto la barra delle app superiore. Il widget Scheda da solo non dispone di informazioni sufficienti per essere visualizzato, quindi lo incapsuleremo in un widget GridView.

Sostituisci Center nel corpo di Scaffold con GridView:

// TODO: Add a grid view (102)
body: GridView.count(
  crossAxisCount: 2,
  padding: const EdgeInsets.all(16.0),
  childAspectRatio: 8.0 / 9.0,
  // TODO: Build a grid of cards (102)
  children: <Widget>[Card()],
),

Analizziamo questo codice. GridView richiama il costruttore count() poiché il numero di elementi visualizzati è numerabile e non infinito. Tuttavia, ha bisogno di maggiori informazioni per definire il layout.

crossAxisCount: specifica il numero di elementi in orizzontale. Vogliamo due colonne.

Il campo padding: fornisce spazio su tutti e quattro i lati di GridView. Ovviamente non puoi vedere il padding sui lati finale o inferiore perché non ci sono ancora elementi secondari GridView accanto.

Il campo childAspectRatio: identifica le dimensioni degli elementi in base a un rapporto di aspetto (larghezza su altezza).

Per impostazione predefinita, GridView crea riquadri tutti delle stesse dimensioni.

Abbiamo una carta, ma è vuota. Aggiungiamo i widget per bambini alla nostra scheda.

Disporre i contenuti

Le schede devono avere regioni per un'immagine, un titolo e un testo secondario.

Aggiorna i figli di GridView:

// TODO: Build a grid of cards (102)
children: <Widget>[
  Card(
    clipBehavior: Clip.antiAlias,
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        AspectRatio(
          aspectRatio: 18.0 / 11.0,
          child: Image.asset('assets/diamond.png'),
        ),
        Padding(
          padding: const EdgeInsets.fromLTRB(16.0, 12.0, 16.0, 8.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              Text('Title'),
              const SizedBox(height: 8.0),
              Text('Secondary Text'),
            ],
          ),
        ),
      ],
    ),
  )
],

Questo codice aggiunge un widget Colonna utilizzato per disporre i widget secondari verticalmente.

crossAxisAlignment: field specifica CrossAxisAlignment.start, che significa "allinea il testo al bordo iniziale".

Il widget AspectRatio decide la forma dell'immagine indipendentemente dal tipo di immagine fornita.

Il padding sposta leggermente il testo dal lato.

I due widget Testo sono impilati verticalmente con 8 punti di spazio vuoto tra di loro (SizedBox). Creiamo un'altra colonna per inserirli all'interno del riempimento.

Salvare il progetto.

Android

iOS

un singolo elemento con un&#39;immagine, un titolo e un testo secondario

un singolo elemento con un&#39;immagine, un titolo e un testo secondario

In questa anteprima, puoi vedere che la scheda è rientrata dal bordo, con angoli arrotondati e un'ombra (che esprime l'elevazione della scheda). L'intera forma è chiamata "contenitore" in Material. Da non confondere con la classe del widget effettivo chiamata Container.

Le carte vengono solitamente mostrate in una raccolta con altre carte. Disponiamoli come raccolta in una griglia.

6. Crea una raccolta di schede

Quando in una schermata sono presenti più schede, queste vengono raggruppate in una o più raccolte. Le carte di una raccolta sono complanari, ovvero condividono la stessa elevazione di riposo (a meno che non vengano sollevate o trascinate, ma non lo faremo qui).

Moltiplicare la carta in una raccolta

Al momento, la nostra scheda è costruita in linea con il campo children: di GridView. Si tratta di un sacco di codice nidificato che può essere difficile da leggere. Estraiamolo in una funzione che può generare tutte le schede vuote che vogliamo e restituisce un elenco di schede.

Crea una nuova funzione privata sopra la funzione build() (ricorda che le funzioni che iniziano con un trattino basso sono API private):

// TODO: Make a collection of cards (102)
List<Card> _buildGridCards(int count) {
  List<Card> cards = List.generate(
    count,
    (int index) {
      return Card(
        clipBehavior: Clip.antiAlias,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            AspectRatio(
              aspectRatio: 18.0 / 11.0,
              child: Image.asset('assets/diamond.png'),
            ),
            Padding(
              padding: const EdgeInsets.fromLTRB(16.0, 12.0, 16.0, 8.0),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: const <Widget>[
                  Text('Title'),
                  SizedBox(height: 8.0),
                  Text('Secondary Text'),
                ],
              ),
            ),
          ],
        ),
      );
    },
  );
  return cards;
}

Assegna le schede generate al campo children di GridView. Ricorda di sostituire tutto ciò che è contenuto in GridView con questo nuovo codice:

// TODO: Add a grid view (102)
body: GridView.count(
  crossAxisCount: 2,
  padding: const EdgeInsets.all(16.0),
  childAspectRatio: 8.0 / 9.0,
  children: _buildGridCards(10) // Replace
),

Salvare il progetto.

Android

iOS

una griglia di elementi con un&#39;immagine, un titolo e un testo secondario

una griglia di elementi con un&#39;immagine, un titolo e un testo secondario

Le schede sono presenti, ma non mostrano ancora nulla. Ora è il momento di aggiungere i dati di prodotto.

Aggiungere i dati di prodotto

L'app ha alcuni prodotti con immagini, nomi e prezzi. Aggiungiamolo ai widget già presenti nella scheda.

Poi, in home.dart, importa un nuovo pacchetto e alcuni file che abbiamo fornito per un modello di dati:

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';

import 'model/product.dart';
import 'model/products_repository.dart';

Infine, modifica _buildGridCards() per recuperare le informazioni sul prodotto e utilizzare questi dati nelle schede:

// TODO: Make a collection of cards (102)

// Replace this entire method
List<Card> _buildGridCards(BuildContext context) {
  List<Product> products = ProductsRepository.loadProducts(Category.all);

  if (products.isEmpty) {
    return const <Card>[];
  }

  final ThemeData theme = Theme.of(context);
  final NumberFormat formatter = NumberFormat.simpleCurrency(
      locale: Localizations.localeOf(context).toString());

  return products.map((product) {
    return Card(
      clipBehavior: Clip.antiAlias,
      // TODO: Adjust card heights (103)
      child: Column(
        // TODO: Center items on the card (103)
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          AspectRatio(
            aspectRatio: 18 / 11,
            child: Image.asset(
              product.assetName,
              package: product.assetPackage,
             // TODO: Adjust the box size (102)
            ),
          ),
          Expanded(
            child: Padding(
              padding: const EdgeInsets.fromLTRB(16.0, 12.0, 16.0, 8.0),
              child: Column(
               // TODO: Align labels to the bottom and center (103)
               crossAxisAlignment: CrossAxisAlignment.start,
                // TODO: Change innermost Column (103)
                children: <Widget>[
                 // TODO: Handle overflowing labels (103)
                 Text(
                    product.name,
                    style: theme.textTheme.titleLarge,
                    maxLines: 1,
                  ),
                  const SizedBox(height: 8.0),
                  Text(
                    formatter.format(product.price),
                    style: theme.textTheme.titleSmall,
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }).toList();
}

NOTA: non verrà ancora compilato ed eseguito. Abbiamo un'altra modifica.

Inoltre, modifica la funzione build() per passare BuildContext a _buildGridCards() prima di tentare la compilazione:

// TODO: Add a grid view (102)
body: GridView.count(
  crossAxisCount: 2,
  padding: const EdgeInsets.all(16.0),
  childAspectRatio: 8.0 / 9.0,
  children: _buildGridCards(context) // Changed code
),

Riavvia l'app.

Android

iOS

una griglia di elementi con un&#39;immagine, il titolo del prodotto e il prezzo

una griglia di elementi con un&#39;immagine, il titolo del prodotto e il prezzo

Potresti notare che non aggiungiamo spazio verticale tra le schede. Questo perché, per impostazione predefinita, hanno un margine di 4 punti in alto e in basso.

Salvare il progetto.

I dati di prodotto vengono visualizzati, ma le immagini hanno spazio aggiuntivo intorno. Le immagini vengono disegnate con un BoxFit di .scaleDown per impostazione predefinita (in questo caso). Modifichiamo il valore in .fitWidth in modo che lo zoom sia leggermente più ravvicinato e lo spazio vuoto in eccesso venga rimosso.

Aggiungi un campo fit: all'immagine con un valore di BoxFit.fitWidth:

  // TODO: Adjust the box size (102)
  fit: BoxFit.fitWidth,

Android

iOS

una griglia di elementi con un&#39;immagine ritagliata, il titolo del prodotto e il prezzo

I nostri prodotti ora vengono visualizzati perfettamente nell'app.

7. Complimenti!

La nostra app ha un flusso di base che porta l'utente dalla schermata di accesso a una schermata Home, dove è possibile visualizzare i prodotti. Con poche righe di codice, abbiamo aggiunto una barra dell'app superiore (con un titolo e tre pulsanti) e schede (per presentare i contenuti della nostra app). La nostra schermata Home è ora semplice e funzionale, con una struttura di base e contenuti su cui è possibile intervenire.

Passaggi successivi

Con la barra delle app superiore, la scheda, il campo di testo e il pulsante, ora abbiamo utilizzato quattro componenti principali della libreria Material Flutter. Per saperne di più, visita il catalogo dei widget dei componenti Material.

Sebbene sia completamente funzionante, la nostra app non esprime ancora un brand o un punto di vista particolare. In MDC-103: Material Design Theming with Color, Shape, Elevation and Type, personalizzeremo lo stile di questi componenti per esprimere un brand vivace e moderno.

Sono riuscito a completare questo codelab con un ragionevole dispendio di tempo e impegno

Totalmente d'accordo D'accordo Indifferente In disaccordo Totalmente in disaccordo

Vorrei continuare a utilizzare i componenti Material in futuro

Totalmente d'accordo D'accordo Indifferente In disaccordo Totalmente in disaccordo