MDC-102 Flutter: struttura e layout del materiale

1. Introduzione

logo_components_color_2x_web_96dp.png

Material Components (MDC) consente agli sviluppatori di implementare Material Design. Creato dal team di ingegneri e designer UX di Google, MDC è dotato di 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 onde di inchiostro. Esaminiamo queste basi aggiungendo navigazione, struttura e dati.

Cosa creerai

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

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

Android

iOS

app di e-commerce con una barra delle app in alto e una griglia piena di prodotti

app di e-commerce con una barra delle app in alto e una griglia piena di prodotti

Componenti e sottosistemi di Material Flutter in questo codelab

  • Barra delle app in alto
  • Griglie
  • Carte

Come valuteresti il tuo livello di esperienza nello sviluppo di Flutter?

Principiante Livello intermedio Eccellente

2. Configura l'ambiente di sviluppo di Flutter

Per completare questo lab sono necessari due software: l'SDK Flutter e l'editor.

Puoi eseguire il codelab utilizzando uno 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 (per il debug è richiesto Chrome).
  • Come applicazione desktop Windows, Linux o macOS. Devi svilupparle sulla piattaforma in cui prevedi di eseguire il deployment. Quindi, se vuoi sviluppare un'app desktop per Windows, devi sviluppare su Windows per accedere alla catena di build appropriata. Alcuni requisiti specifici del sistema operativo sono descritti in dettaglio all'indirizzo docs.flutter.dev/desktop.

3. Scarica l'app iniziale del codelab

Vuoi continuare da MDC-101?

Se hai completato MDC-101, il tuo codice dovrebbe essere preparato per questo codelab. Vai al passaggio Aggiungi una barra delle app in alto.

Vuoi iniziare da zero?

Scarica l'app codelab iniziale

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

...o clonarlo da GitHub

Per clonare questo codelab da GitHub, esegui questi 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 "Esegui l'app". in Inizia: prova l'editor che hai scelto.

Operazione riuscita. Dovresti visualizzare la pagina di accesso a Santuario del codelab MDC-101 sul tuo dispositivo.

Android

iOS

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

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

Ora che la schermata di accesso è corretta, aggiungiamo alcuni prodotti all'app.

4. Aggiungi una barra delle app in alto

Al momento, se fai clic sul pulsante "Avanti" potrai visualizzare la schermata Home con il messaggio "Ce l'hai fatta!". Fantastico. Ora invece i nostri utenti non hanno azioni da intraprendere o hanno la sensazione di dove si trovano nell'app. Per aiutarti, è il momento di aggiungere la navigazione.

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

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

Aggiungere un widget AppBar

In home.dart, aggiungi un'AppBar allo Scaffold e rimuovi la const evidenziata:

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 permette di avere un layout senza costi perfetto, mantenendo l'AppBar nella parte superiore della pagina e il corpo sotto.

Aggiungere un widget Testo

In home.dart, aggiungi un titolo all'AppBar:

// 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 il titolo Santuario

una barra delle app con il titolo Santuario

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

Aggiungi un IconButton principale

Sempre in home.dart, imposta un IconButton per il campo leading: di AppBar. Inseriscilo prima del campo title: per simulare l'ordine iniziale alla fine:

    // 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 il titolo del santuario e l'icona di un menu a tre linee

una barra delle app con il titolo del santuario e l'icona di un menu a tre linee

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

Puoi anche aggiungere pulsanti alla fine del titolo. In Flutter, queste sono chiamate "azioni".

Aggiungere azioni

C'è spazio per altri due pulsanti IconButton.

Aggiungile 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 avere il seguente aspetto:

Android

iOS

una barra delle app con Santuario come titolo e un&#39;icona di menu a tre linee, oltre a icone di ricerca e personalizzazione finali

una barra delle app con Santuario come titolo e un&#39;icona di menu a tre linee, oltre a icone di ricerca e personalizzazione finali

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

5. Aggiungi una scheda in una griglia

Ora che la nostra app ha una struttura ben strutturata, organizza i contenuti inserendoli in schede.

Aggiungi una griglia

Inizia aggiungendo una scheda sotto la barra delle app in alto. Il widget Scheda da solo non dispone di informazioni sufficienti per posizionarsi dove possiamo vederlo, quindi vogliamo incorporarlo in un widget GridView.

Sostituisci il centro nel corpo della piattaforma con una visualizzazione griglia:

// 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()],
),

Apriamo il codice. GridView richiama il costruttore count() poiché il numero di elementi che visualizza è numerabile e non infinito. ma ha bisogno di ulteriori informazioni per definirne il layout.

L'crossAxisCount: specifica il numero di elementi. Vogliamo 2 colonne.

Il campo padding: offre spazio su tutti e quattro i lati di GridView. Ovviamente non puoi vedere la spaziatura interna sui lati finali o inferiori perché non ci sono ancora elementi secondari GridView accanto.

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

Per impostazione predefinita, GridView crea riquadri della stessa dimensione.

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

Layout dei contenuti

Le schede devono includere aree per un'immagine, un titolo e un testo secondario.

Aggiorna gli elementi secondari 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.

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

Il widget AspectRatio stabilisce la forma che assume l'immagine, indipendentemente dal tipo di immagine fornita.

Spaziatura interna avvicina un po' il testo lateralmente.

I due widget Testo sono impilati verticalmente e separati da 8 punti di spazio vuoto (SizedBox). Creiamo un'altra colonna per ospitarli nella Spaziatura interna.

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 è inserita dal bordo, con gli angoli arrotondati e un'ombra (che indica l'elevazione della scheda). L'intera forma è chiamata "contenitore" in Material. (da non confondere con l'effettiva classe widget chiamata Container).

In genere le schede vengono mostrate in una raccolta insieme ad altre schede. Disponiamole come una raccolta in una griglia.

6. Crea una raccolta di schede

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

Moltiplicare la scheda in una raccolta

Al momento la nostra scheda è creata in linea nel campo children: di GridView. Si tratta di una grande quantità di codice nidificato che può essere difficile da leggere. Estraiamolo in una funzione in grado di generare tutte le schede vuote che vogliamo e che restituisce un elenco di schede.

Crea una nuova funzione privata sopra la funzione build() (ricorda che le funzioni che iniziano con il 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. È 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

Quindi, in home.dart, importa un nuovo pacchetto e alcuni file forniti per un modello dei 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 i dati presenti 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 compilata ed eseguita. Abbiamo un'altra modifica.

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

// 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 a caldo.

Android

iOS

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

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

Potresti notare che non viene aggiunto alcuno spazio verticale tra le schede. Questo perché, per impostazione predefinita, sono presenti 4 punti di margine nella parte superiore e in quella inferiore.

Salvare il progetto.

Vengono visualizzati i dati di prodotto, ma intorno alle immagini c'è altro spazio. Per impostazione predefinita, le immagini sono disegnate con un elemento BoxFit di .scaleDown (in questo caso). Cambiamo l'impostazione in .fitWidth in modo che aumentino lo zoom e rimuoviamo gli spazi vuoti aggiuntivi.

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

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

Android

iOS

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

I nostri prodotti vengono ora visualizzati perfettamente nell'app.

7. Complimenti!

La nostra app prevede un flusso di base che porta l'utente dalla schermata di accesso a una schermata Home in cui è possibile visualizzare i prodotti. In poche righe di codice, abbiamo aggiunto una barra delle app in alto (con un titolo e tre pulsanti) e delle schede (per presentare i contenuti della nostra app). La nostra schermata Home ora è semplice e funzionale, con una struttura di base e contenuti interattivi.

Passaggi successivi

Con la barra delle app, la scheda, il campo di testo e il pulsante in alto, 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 alcun brand o punto di vista in particolare. In MDC-103: Tema di Material Design con colore, forma, altezza e tipo, personalizzeremo lo stile di questi componenti per esprimere un brand vivace e moderno.

Ho completato questo codelab con una quantità di tempo e di sforzi ragionevoli

Totalmente d'accordo D'accordo Né chiara, né confusa In disaccordo Totalmente in disaccordo

Vorrei continuare a utilizzare Material Components in futuro

Totalmente d'accordo D'accordo Né chiara, né confusa In disaccordo Totalmente in disaccordo