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

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

Ora puoi utilizzare Material Flutter per personalizzare lo stile distintivo delle tue app più che mai. La recente espansione di Material Design offre a designer e sviluppatori una maggiore flessibilità per esprimere il brand del proprio 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, quindi porta l'utente a una schermata Home che mostra i prodotti.

Cosa creerai

In questo codelab, personalizzerai l'app Shrine utilizzando:

  • Colore
  • Tipografia
  • Elevazione
  • Forma
  • Layout

Android

iOS

Pagina di accesso al santuario, a tema marrone e rosa

Pagina di accesso al santuario, a tema marrone e rosa

Pagina prodotto di un santuario, con una barra delle app in alto e una griglia asimmetrica scorrevole orizzontalmente piena di prodotti, a tema rosa

Componenti e sottosistemi Material Flutter in questo codelab

  • Temi
  • Tipografia
  • Elevazione
  • Elenco immagini

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

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

Partire 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 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 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 "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 delle codelab precedenti.

Android

iOS

Pagina di accesso Shrine senza tema

Pagina di accesso Shrine senza tema

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

Android

iOS

pagina della griglia dei prodotti Shrine senza tema

pagina della griglia dei prodotti Shrine senza tema

4. Cambiare i colori

È stata creata una combinazione di colori che rappresenta il brand Shrine e il designer vorrebbe che tu la implementassi nell'app Shrine

Per iniziare, importiamo questi colori nel nostro progetto.

Crea colors.dart

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

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 di colori è stato creato da un designer con colori personalizzati (mostrati nell'immagine di seguito). Contiene colori selezionati dal brand di Shrine e applicati a Material Theme Editor, che li ha espansi per creare una tavolozza più completa. Questi colori non provengono dalle tavolozze dei colori Material del 2014.

L'editor del tema Material li ha organizzati in tonalità etichettate numericamente, incluse le etichette 50, 100, 200, ... fino a 900 di ogni colore. Shrine utilizza solo le tonalità 50, 100 e 300 del campione rosa e 900 del campione marrone.

d0362cb45c565a8e.jpeg 470b0e1c2669ae2.png

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

Ora che abbiamo i colori che vogliamo utilizzare, possiamo applicarli all'interfaccia utente. Lo faremo impostando i valori di un widget ThemeData che applichiamo all'istanza MaterialApp nella parte superiore della gerarchia dei widget.

Personalizza 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.dart al di fuori dell'ambito della classe ShrineApp:

// 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 ShrineApp (nel widget MaterialApp) in modo che sia il nostro nuovo tema:

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

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

Android

iOS

Pagina di accesso di Shrine con tema rosa e marrone

Pagina di accesso di Shrine con tema rosa e marrone

5. Modificare gli stili di tipografia ed etichette

Oltre alle modifiche del colore, il designer ci ha anche fornito una tipografia specifica da utilizzare. ThemeData di Flutter include tre temi di testo. Ogni tema di testo è una raccolta di stili di testo, come "titolo" e "intestazione". Utilizzeremo alcuni stili per la nostra app e modificheremo 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.

Risoluzione dei problemi relativi al file pubspec

Potresti riscontrare errori durante l'esecuzione di pub get se tagli e incolli la dichiarazione riportata sopra. Se ricevi errori, inizia rimuovendo gli spazi bianchi iniziali e sostituendoli con spazi utilizzando un rientro di due spazi. (Due spazi prima

fonts:

, quattro spazi prima

family: Rubik

, e così via).

Se viene visualizzato il messaggio La mappatura dei valori non è consentita qui, controlla il rientro della riga che presenta il problema e di quelle sopra.

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,
      );
}

Prende un TextTheme e modifica l'aspetto di titoli, sottotitoli e didascalie.

L'applicazione di fontFamily in questo modo applica le modifiche solo ai valori della scala tipografica specificati in copyWith() (titolo, titolo, didascalia).

Per alcuni caratteri, impostiamo un fontWeight personalizzato, con incrementi di 100: w500 (il peso 500) corrisponde a medio e w400 a normale.

Utilizzare i nuovi temi

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 rapido), poiché abbiamo modificato i caratteri.

Android

iOS

Pagina della griglia dei prodotti Shrine con temi di testo applicati

Il testo nelle schermate di accesso e Home ha un aspetto diverso: alcuni testi utilizzano il carattere Rubik, mentre altri vengono visualizzati in marrone anziché in nero o bianco. Anche le icone vengono visualizzate in marrone.

Ridurre il testo

Le etichette sono troppo grandi.

In home.dart, modifica 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
],

Centrare e rilasciare 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 centrarle:

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

Salvare il progetto.

Android

iOS

Pagina della griglia dei prodotti del santuario con allineamento del testo diverso

Pagina della griglia dei prodotti del santuario con allineamento del testo diverso

Ora va molto meglio.

Applicare un tema ai campi di testo

Puoi anche applicare un tema alla decorazione dei 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. Rimuoviamolo. Se rimuovi filled e specifichi inputDecorationTheme, i campi di testo avranno 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. La schermata di accesso dovrebbe essere simile a questa quando il campo Nome utente è attivo (quando stai digitando):

Android

iOS

Pagina di accesso di Shrine con il campo del nome utente selezionato

Pagina di accesso di Shrine con il campo del nome utente selezionato

Digita in un campo di testo: i bordi e le etichette mobili vengono visualizzati nel colore principale. ma non è facile vederlo. Non è accessibile alle persone che hanno difficoltà a distinguere i pixel che non hanno un contrasto cromatico sufficiente. Per saperne di più, consulta l'articolo su colore e accessibilità delle linee guida di Material Design.

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 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, facciamo in modo 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 di Shrine con pulsante ANNULLA accessibile

Pagina di accesso di Shrine con pulsante ANNULLA accessibile

6. Regolare l'elevazione

Ora che hai applicato uno stile alla pagina con colori e tipografia specifici che corrispondono a Shrine, regoliamo l'elevazione.

Modificare l'elevazione del pulsante AVANTI

L'elevazione predefinita per un ElevatedButton è 2. Alziamolo ancora un po'.

In login.dart, aggiungi un valore style: all'ElevatedButton 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 a Shrine con il pulsante AVANTI in evidenza

Pagina di accesso a Shrine con il pulsante AVANTI in evidenza

Regolare l'elevazione della scheda

Al momento, le schede si trovano su una superficie bianca accanto alla navigazione del sito.

In home.dart, aggiungi un valore elevation: a Carte:

// 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 interessante, che definisce gli elementi con una forma ottagonale o rettangolare. Implementiamo lo stile della forma nelle schede della schermata Home e nei campi di testo e nei pulsanti della schermata di accesso.

Modificare 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 di decorazione del campo di testo in modo che utilizzi un bordo con angoli smussati:

// 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, quindi perché aggiungere una forma del bordo? Pertanto, l'animazione a increspatura è associata 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 utilizzare anche elevatedButtonTheme o textButtonTheme in app.dart. Lasciamo questa sfida allo studente.

Riavvio a caldo.

Android

iOS

Pagina di accesso di Shrine con applicazione del tema delle forme

Pagina di accesso di Shrine con applicazione del tema delle forme

8. Modificare il layout

Successivamente, modifichiamo il layout per mostrare le schede con proporzioni e dimensioni diverse, in modo che ogni scheda sia diversa dalle altre.

Sostituisci 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 di prodotto Shrine con layout asimmetrico scorrevole orizzontalmente

Pagina di prodotto Shrine con layout asimmetrico scorrevole orizzontalmente

Ora i prodotti scorrono orizzontalmente in un motivo ispirato a una trama.

9. Prova un altro tema (facoltativo)

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 fare una prova, vediamo come appare Shrine 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() nel seguente modo:

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. Ora dovrebbe essere visualizzato il nuovo tema.

Android

iOS

Pagina di accesso al santuario con un tema viola e rosa

Pagina di accesso al santuario con un tema viola e rosa

Android

iOS

Pagina prodotto del santuario con tema rosa

Pagina prodotto del santuario con tema rosa

Il risultato è molto diverso. Ripristiniamo app.dart's _buildShrineTheme allo stato precedente a questo passaggio. In alternativa, scarica il codice di avvio di 104.

10. Complimenti!

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

Passaggi successivi

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

Esplora i file nella directory supplemental per scoprire come abbiamo creato la griglia di layout asimmetrica a scorrimento orizzontale.

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

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