MDC-103 Flutter: temi Material con Colore, Forma, Elevazione e Tipo

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

Ora puoi usare Material Flutter per personalizzare le tue app e uno stile distintivo più che mai. La recente espansione di Material Design offre a designer e sviluppatori una maggiore flessibilità per esprimere il brand del prodotto.

Nei codelab MDC-101 e MDC-102,hai utilizzato Material Flutter per creare le basi di un'app chiamata Shrine, un'app di e-commerce che vende abbigliamento e articoli per la casa. Questa app contiene un flusso utente che inizia con una schermata di accesso, poi rimanda l'utente a una schermata Home in cui sono visualizzati i prodotti.

Cosa creerai

In questo codelab personalizzerai l'app Santuario utilizzando:

  • Colore
  • Tipografia
  • Elevazione
  • Shape
  • Layout

Android

iOS

Pagina di accesso al santuario, marrone e rosa a tema

Pagina di accesso al santuario, marrone e rosa a tema

Pagina del prodotto del santuario, con una barra delle app nella parte superiore e una griglia asimmetrica, scorrevole in orizzontale, piena di prodotti, a tema rosa

Componenti e sottosistemi di Material Flutter in questo codelab

  • Temi
  • Tipografia
  • Elevazione
  • Elenco immagini

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-102?

Se hai completato MDC-102, il tuo codice dovrebbe essere pronto per questo codelab. Vai al passaggio Cambia colori.

Vuoi iniziare da zero?

Scarica l'app codelab iniziale

L'app iniziale si trova nella directory material-components-flutter-codelabs-103-starter_and_102-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 103-starter_and_102-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. Sul tuo dispositivo dovresti visualizzare la pagina di accesso a Santuario dei codelab precedenti.

Android

iOS

pagina di accesso a Santuario senza tema

pagina di accesso a Santuario senza tema

Fai clic su "Avanti" per visualizzare la pagina del prodotto.

Android

iOS

pagina della griglia dei prodotti del santuario senza tema

pagina della griglia dei prodotti del santuario senza tema

4. Cambiare i colori

È stata creata una combinazione di colori che rappresenta il brand Santuario e il designer vorrebbe che lo implementi nell'app Santuario.

Per iniziare, importa quei colori nel nostro progetto.

Crea colors.dart

Crea un nuovo file di freccette in lib denominato colors.dart. Importa material.dart e aggiungi const Color valori:

import 'package:flutter/material.dart';

const kShrinePink50 = Color(0xFFFEEAE6);
const kShrinePink100 = Color(0xFFFEDBD0);
const kShrinePink300 = Color(0xFFFBB8AC);
const kShrinePink400 = Color(0xFFEAA4A4);

const kShrineBrown900 = Color(0xFF442B2D);

const kShrineErrorRed = Color(0xFFC5032B);

const kShrineSurfaceWhite = Color(0xFFFFFBFA);
const kShrineBackgroundWhite = Colors.white;

Tavolozza dei colori personalizzata

Questo tema a colori è stato creato da un designer con colori personalizzati (mostrati nell'immagine di seguito). Contiene colori che sono stati selezionati dal brand di Santuario e applicati all'editor dei temi materiali, che li ha ampliati per creare una tavolozza più completa. Questi colori non provengono dalle tavolozze dei colori Material 2014.

L'editor dei temi materiali li ha organizzati in tonalità etichettate numericamente, incluse le etichette 50, 100, 200, ... a 900 di ciascun colore. Santuario usa solo le tonalità 50, 100 e 300 del campione rosa e 900 del campione marrone.

d0362cb45c565a8e.jpeg 470b0e1c2669ae2.png

Ogni parametro del colore di un widget è mappato a un colore di questi schemi. Ad esempio, il colore delle decorazioni di un campo di testo quando riceve attivamente input dovrebbe essere il colore principale del tema. Se quel colore non è accessibile (facile da vedere sullo sfondo), utilizzane un altro.

Ora che abbiamo i colori che vogliamo usare, possiamo applicarli alla UI. Per farlo, imposta i valori di un widget ThemeData che applichiamo all'istanza di MaterialApp nella parte superiore della gerarchia dei widget.

Personalizzare ThemeData.light()

Flutter include alcuni temi integrati. Il tema chiaro è uno di questi. Anziché creare un widget ThemeData da zero, copieremo il tema chiaro e modificheremo i valori per personalizzarli per la nostra app.

Importiamo colors.dart in app.dart.

import 'colors.dart';

Quindi aggiungi quanto segue ad app.ARROW al di fuori dell'ambito della classe SantuarioApp:

// TODO: Build a Shrine Theme (103)
final ThemeData _kShrineTheme = _buildShrineTheme();

ThemeData _buildShrineTheme() {
  final ThemeData base = ThemeData.light(useMaterial3: true);
  return base.copyWith(
    colorScheme: base.colorScheme.copyWith(
      primary: kShrinePink100,
      onPrimary: kShrineBrown900,
      secondary: kShrineBrown900,
      error: kShrineErrorRed,
    ),
    // TODO: Add the text themes (103)
    // TODO: Decorate the inputs (103)
  );
}

Ora, imposta theme: alla fine della funzione build() di SantuarioApp (nel widget MaterialApp) come nuovo tema:

  // TODO: Customize the theme (103)
  theme: _kShrineTheme, // New code

Salvare il progetto. La schermata di accesso dovrebbe avere il seguente aspetto:

Android

iOS

pagina di accesso al Santuario con tema rosa e marrone

pagina di accesso al Santuario con tema rosa e marrone

5. Modificare gli stili di tipografia e di etichetta

Oltre alle modifiche di colore, il designer ci ha anche fornito elementi tipografici specifici da utilizzare. ThemeData di Flutter include tre temi di testo. Ogni tema del testo è una raccolta di stili di testo, ad esempio "titolo" e "title". Utilizzeremo alcuni stili per l'app e cambieremo alcuni valori.

Personalizzare il tema del testo

Per importare i caratteri nel progetto, devono essere aggiunti al file pubspec.yaml.

In pubspec.yaml, aggiungi quanto segue subito dopo il tag flutter::

  # TODO: Insert Fonts (103)
  fonts:
    - family: Rubik
      fonts:
        - asset: fonts/Rubik-Regular.ttf
        - asset: fonts/Rubik-Medium.ttf
          weight: 500

Ora puoi accedere al carattere Rubik e utilizzarlo.

Risolvere i problemi relativi al file pubspec

Potresti visualizzare errori durante l'esecuzione di pub get se tagli e incolli la dichiarazione riportata sopra. Se visualizzi errori, inizia rimuovendo lo spazio vuoto iniziale e sostituendolo con spazi usando il rientro di due spazi. (due spazi prima

fonts:

, quattro spazi prima

family: Rubik

e così via).

Se viene visualizzato il messaggio I valori di mappatura non sono consentiti qui, controlla il rientro della linea che presenta il problema e il rientro delle righe superiori.

In login.dart, modifica quanto segue all'interno di Column():

Column(
  children: <Widget>[
    Image.asset('assets/diamond.png'),
    const SizedBox(height: 16.0),
    Text(
      'SHRINE',
      style: Theme.of(context).textTheme.headlineSmall,
    ),
  ],
)

In app.dart, aggiungi quanto segue dopo _buildShrineTheme():

// TODO: Build a Shrine Text Theme (103)
TextTheme _buildShrineTextTheme(TextTheme base) {
  return base
      .copyWith(
        headlineSmall: base.headlineSmall!.copyWith(
          fontWeight: FontWeight.w500,
        ),
        titleLarge: base.titleLarge!.copyWith(
          fontSize: 18.0,
        ),
        bodySmall: base.bodySmall!.copyWith(
          fontWeight: FontWeight.w400,
          fontSize: 14.0,
        ),
        bodyLarge: base.bodyLarge!.copyWith(
          fontWeight: FontWeight.w500,
          fontSize: 16.0,
        ),
      )
      .apply(
        fontFamily: 'Rubik',
        displayColor: kShrineBrown900,
        bodyColor: kShrineBrown900,
      );
}

Viene preso un TextTheme e viene modificato l'aspetto di titoli, titoli e sottotitoli.

Applicando l'fontFamily in questo modo, le modifiche vengono applicate solo ai valori della scala tipografia specificati in copyWith() (titolo, titolo, didascalia).

Per alcuni caratteri, stiamo impostando un peso del carattere personalizzato con incrementi di 100: w500 (peso pari a 500) corrisponde a mezzo e w400 corrisponde a regolare.

Utilizzare i nuovitemi di testo

Aggiungi i seguenti temi a _buildShrineTheme dopo l'errore:

// TODO: Add the text themes (103)
textTheme: _buildShrineTextTheme(base.textTheme),
textSelectionTheme: const TextSelectionThemeData(
  selectionColor: kShrinePink100,
),

Salvare il progetto. Questa volta riavvia anche l'app (operazione nota come riavvio a caldo), dato che abbiamo modificato i caratteri.

Android

iOS

Pagina della griglia dei prodotti del santuario con temi di testo applicati

Il testo nelle schermate di accesso e in quello Home ha un aspetto diverso: parte del testo utilizza il carattere Rubik, mentre l'altro viene visualizzato in marrone anziché in bianco o nero. Anche le icone vengono visualizzate in marrone.

Ridurre il testo

Le etichette sono troppo grandi.

In home.dart, modifica il valore children: della colonna più interna:

// TODO: Change innermost Column (103)
children: <Widget>[
// TODO: Handle overflowing labels (103)
  Text(
    product.name,
    style: theme.textTheme.button,
    softWrap: false,
    overflow: TextOverflow.ellipsis,
    maxLines: 1,
  ),
  const SizedBox(height: 4.0),
  Text(
    formatter.format(product.price),
    style: theme.textTheme.bodySmall,
  ),
  // End new code
],

Centra e rilascia il testo

Vogliamo centrare le etichette e allineare il testo alla parte inferiore di ogni scheda, anziché alla parte inferiore di ogni immagine.

Sposta le etichette alla fine (in basso) dell'asse principale e modificale per centrarle:

  // TODO: Align labels to the bottom and center (103)
  mainAxisAlignment: MainAxisAlignment.end,
  crossAxisAlignment: CrossAxisAlignment.center,

Salvare il progetto.

Android

iOS

Pagina della griglia del prodotto del santuario con allineamento del testo diverso

Pagina della griglia del prodotto del santuario con allineamento del testo diverso

Sembra molto meglio.

Creare un tema per i campi di testo

Puoi anche scegliere un tema per la decorazione nei campi di testo con un InputDecorationTheme.

In app.dart, nel metodo _buildShrineTheme(), specifica un valore inputDecorationTheme::

// TODO: Decorate the inputs (103)
inputDecorationTheme: const InputDecorationTheme(
  border: OutlineInputBorder(),
),

Al momento, i campi di testo hanno una decorazione filled. Rimuoviamo l'elemento. Se rimuovi filled e specifichi il valore inputDecorationTheme, ai campi di testo verrà applicato lo stile del contorno.

In login.dart, rimuovi i valori filled: true:

// Remove filled: true values (103)
TextField(
  controller: _usernameController,
  decoration: const InputDecoration(
    // Removed filled: true
    labelText: 'Username',
  ),
),
const SizedBox(height: 12.0),
TextField(
  controller: _passwordController,
  decoration: const InputDecoration(
    // Removed filled: true
    labelText: 'Password',
  ),
  obscureText: true,
),

Riavvio a caldo. Quando il campo Nome utente è attivo (durante la digitazione), la schermata di accesso dovrebbe avere il seguente aspetto:

Android

iOS

Pagina di accesso al santuario con il campo del nome utente evidenziato

Pagina di accesso al santuario con il campo del nome utente evidenziato

Digita in un campo di testo: i bordi e le etichette mobili vengono visualizzati con il colore principale. Ma non è facile vederli. Non sono accessibili da chi ha difficoltà a distinguere i pixel che non hanno un contrasto di colore sufficientemente elevato. Per ulteriori informazioni, leggi l'articolo su colore e accessibilità delle linee guida sui materiali.

In app.dart, specifica un focusedBorder: in inputDecorationTheme: :

// TODO: Decorate the inputs (103)
inputDecorationTheme: const InputDecorationTheme(
  border: OutlineInputBorder(),
  focusedBorder: OutlineInputBorder(
    borderSide: BorderSide(
      width: 2.0,
      color: kShrineBrown900,
    ),
  ),
),

Successivamente, specifica un valore floatingLabelStyle: in inputDecorationTheme: :

// TODO: Decorate the inputs (103)
inputDecorationTheme: const InputDecorationTheme(
  border: OutlineInputBorder(),
  focusedBorder: OutlineInputBorder(
    borderSide: BorderSide(
      width: 2.0,
      color: kShrineBrown900,
    ),
  ),
  floatingLabelStyle: TextStyle(
    color: kShrineBrown900,
  ),
),

Infine, supponiamo che il pulsante Annulla utilizzi il colore secondario anziché quello principale per aumentare il contrasto.

TextButton(
  child: const Text('CANCEL'),
  onPressed: () {
    _usernameController.clear();
    _passwordController.clear();
  },
  style: TextButton.styleFrom(
    primary: Theme.of(context).colorScheme.secondary,
  ),
),

Salvare il progetto.

Android

iOS

Pagina di accesso al santuario con pulsante ANNULLA accessibile

Pagina di accesso al santuario con pulsante ANNULLA accessibile

6. Regola l'elevazione

Ora che hai assegnato alla pagina uno stile specifico e tipografico che corrisponda a Santuario, regola l'elevazione.

Modificare l'elevazione del pulsante SUCCESSIVO

L'elevazione predefinita per ElevatedButton è 2. Saliamo più in alto.

In login.dart, aggiungi un valore style: al pulsante elevato AVANTI:

ElevatedButton(
  child: const Text('NEXT'),
  onPressed: () {
    Navigator.pop(context);
  },
  style: ElevatedButton.styleFrom(
    foregroundColor: kShrineBrown900,
    backgroundColor: kShrinePink100,
    elevation: 8.0,
  ),
),

Salvare il progetto.

Android

iOS

Pagina di accesso al santuario con pulsante SUCCESSIVO elevato

Pagina di accesso al santuario con pulsante SUCCESSIVO elevato

Regola l'elevazione della scheda

In questo momento, le schede sono visibili su una superficie bianca accanto al riquadro di navigazione del sito.

In home.dart, aggiungi un valore elevation: alle schede:

// TODO: Adjust card heights (103)
elevation: 0.0,

Salva il progetto.

Android

iOS

Pagina della griglia dei prodotti del santuario senza elevazione per ogni scheda

Pagina della griglia dei prodotti del santuario senza elevazione per ogni scheda

Hai rimosso l'ombra sotto le carte.

7. Aggiungi forma

Il santuario ha uno stile geometrico trendy, che definisce gli elementi a forma ottagonale o rettangolare. Implementiamo questo stile nelle schede della schermata Home e nei campi di testo e nei pulsanti nella schermata di accesso.

Modifica le forme dei campi di testo nella schermata di accesso

In app.dart, importa il seguente file:

import 'supplemental/cut_corners_border.dart';

Sempre in app.dart, modifica il tema decorativo del campo di testo per utilizzare il bordo degli angoli tagliati:

// TODO: Decorate the inputs (103)
inputDecorationTheme: const InputDecorationTheme(
  border: CutCornersBorder(),
  focusedBorder: CutCornersBorder(
    borderSide: BorderSide(
      width: 2.0,
      color: kShrineBrown900,
    ),
  ), 
  floatingLabelStyle: TextStyle(
    color: kShrineBrown900,
  ),
),

Modificare le forme dei pulsanti nella schermata di accesso

In login.dart, aggiungi un bordo rettangolare smussato al pulsante ANNULLA:

TextButton(
  child: const Text('CANCEL'),
  onPressed: () {
    _usernameController.clear();
    _passwordController.clear();
  },
  style: TextButton.styleFrom(
    foregroundColor: kShrineBrown900,
    shape: const BeveledRectangleBorder(
      borderRadius: BorderRadius.all(Radius.circular(7.0)),
    ),
  ),
),

TextButton non ha una forma visibile, allora perché aggiungere una forma per il bordo? In questo modo, l'animazione a onde viene legata alla stessa forma quando viene toccata.

Ora aggiungi la stessa forma al pulsante AVANTI:

ElevatedButton(
  child: const Text('NEXT'),
  onPressed: () {
    Navigator.pop(context);
  },
  style: ElevatedButton.styleFrom(
    foregroundColor: kShrineBrown900,
    backgroundColor: kShrinePink100,
    elevation: 8.0,
    shape: const BeveledRectangleBorder(
      borderRadius: BorderRadius.all(Radius.circular(7.0)),
    ),
  ),
),

Per modificare la forma di tutti i pulsanti, possiamo usare anche elevatedButtonTheme o textButtonTheme in app.dart. Questo rimane una sfida per lo studente.

Riavvio a caldo.

Android

iOS

Pagina di accesso al santuario con tema forma applicato

Pagina di accesso al santuario con tema forma applicato

8. Modificare il layout

Ora modifichiamo il layout in modo da mostrare le schede con proporzioni e dimensioni diverse, in modo che ogni scheda risulti unica dalle altre.

Sostituire GridView con AsymmetricView

Abbiamo già scritto i file per un layout asimmetrico.

In home.dart, aggiungi la seguente importazione:

import 'supplemental/asymmetric_view.dart';

Elimina _buildGridCards e sostituisci body:

body: AsymmetricView(
  products: ProductsRepository.loadProducts(Category.all),
),

Salva il progetto.

Android

iOS

Pagina del prodotto del santuario con layout a scorrimento orizzontale asimmetrico

Pagina del prodotto del santuario con layout a scorrimento orizzontale asimmetrico

Ora i prodotti scorrono in orizzontale con un motivo ispirato al tessuto.

9. (Facoltativo) Prova con un altro tema

Il colore è un modo efficace per esprimere il tuo brand e un piccolo cambiamento di colore può avere un grande effetto sull'esperienza utente. Per provarlo, vediamo che aspetto ha Santuario se la combinazione di colori del brand fosse leggermente diversa.

Modificare i colori

In colors.dart, aggiungi il seguente colore:

const kShrinePurple = Color(0xFF5D1049);

In app.dart, modifica la funzione _buildShrineTheme() come segue:

ThemeData _buildShrineTheme() {
  final ThemeData base = ThemeData.light();
  return base.copyWith(
    colorScheme: base.colorScheme.copyWith(
      primary: kShrinePurple,
      secondary: kShrinePurple,
      error: kShrineErrorRed,
    ),
    scaffoldBackgroundColor: kShrineSurfaceWhite,
    textSelectionTheme: const TextSelectionThemeData(
      selectionColor: kShrinePurple,
    ),
    appBarTheme: const AppBarTheme(
      foregroundColor: kShrineBrown900,
      backgroundColor: kShrinePink100,
    ),

    inputDecorationTheme: const InputDecorationTheme(
      border: CutCornersBorder(),
      focusedBorder: CutCornersBorder(
        borderSide: BorderSide(
          width: 2.0,
          color: kShrinePurple,
        ),
      ),
      floatingLabelStyle: TextStyle(
        color: kShrinePurple,
      ),
    ),
  );
}

Riavvio a caldo. A questo punto dovrebbe essere visualizzato il nuovo tema.

Android

iOS

Pagina di accesso al santuario a tema viola e rosa

Pagina di accesso al santuario a tema viola e rosa

Android

iOS

Pagina del prodotto del santuario a tema rosa

Pagina del prodotto del santuario a tema rosa

Il risultato è molto diverso. Ripristina app.dart's _buildShrineTheme allo stato che era prima di questo passaggio. In alternativa, scarica il codice di avvio di 104.

10. Complimenti!

A questo punto hai creato un'app che presenta le specifiche di progettazione del tuo designer.

Passaggi successivi

Ora hai utilizzato le seguenti dimensioni di Material Flutter: tema, tipografia, elevazione e forma. Puoi esplorare altri componenti e sottosistemi nella libreria Material Flutter.

Analizza i file nella directory supplemental per scoprire come abbiamo reso la griglia di layout asimmetrico a scorrimento orizzontale.

Cosa succede se il design pianificato dell'app contiene elementi che non hanno componenti nella raccolta? In MDC-104: Material Advanced Components, mostriamo come creare componenti personalizzati utilizzando la libreria Material Flutter per ottenere il look desiderato.

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