MDC-102 Flutter: Materialstruktur und Layout

1. Einführung

logo_components_color_2x_web_96dp.png

Material Components (MDC) unterstützen Entwickler bei der Implementierung von Material Design. MDC wurde von einem Team aus Entwicklern und UX-Designern bei Google entwickelt. Es enthält Dutzende schöne und funktionale UI-Komponenten und ist für Android, iOS, das Web und Flutter.material.io/develop verfügbar.

Im Codelab MDC-101 haben Sie zwei Materialkomponenten zum Erstellen einer Anmeldeseite verwendet: Textfelder und Schaltflächen mit Tintenrippeln. Erweitern wir nun diese Grundlage, indem wir Navigation, Struktur und Daten hinzufügen.

Inhalt

In diesem Codelab erstellen Sie einen Startbildschirm für eine App namens Shrine, eine E-Commerce-App für Kleidung und Haushaltswaren. Sie enthält Folgendes:

  • Obere App-Leiste
  • Eine Rasterliste mit Produkten

Android

iOS

E-Commerce-App mit einer oberen App-Leiste und einem Raster mit Produkten

E-Commerce-App mit einer oberen App-Leiste und einem Raster mit Produkten

Codelab: Material Flutter-Komponenten und -Subsysteme

  • Obere App-Leiste
  • Raster
  • Karten

Wie würden Sie Ihre Erfahrung mit der Flutter-Entwicklung bewerten?

<ph type="x-smartling-placeholder"></ph> Neuling Mittel Kompetent

2. Flutter-Entwicklungsumgebung einrichten

Für dieses Lab benötigen Sie zwei Softwareprogramme: das Flutter SDK und einen Editor.

Sie können das Codelab auf jedem dieser Geräte ausführen:

  • Ein physisches Android- oder iOS, das mit Ihrem Computer verbunden ist und sich im Entwicklermodus befindet.
  • Den iOS-Simulator (erfordert die Installation von Xcode-Tools).
  • Android-Emulator (Einrichtung in Android Studio erforderlich)
  • Ein Browser (zur Fehlerbehebung wird Chrome benötigt)
  • Als Windows-, Linux- oder macOS-Desktopanwendung Die Entwicklung muss auf der Plattform erfolgen, auf der Sie die Bereitstellung planen. Wenn Sie also eine Windows-Desktop-App entwickeln möchten, müssen Sie die Entwicklung unter Windows ausführen, damit Sie auf die entsprechende Build-Kette zugreifen können. Es gibt betriebssystemspezifische Anforderungen, die unter docs.flutter.dev/desktop ausführlich beschrieben werden.

3. Codelab-Starter-App herunterladen

Weiter von MDC-101?

Wenn du MDC-101 abgeschlossen hast, sollte dein Code für dieses Codelab vorbereitet sein. Fahren Sie mit dem Schritt Obene App-Leiste hinzufügen fort.

Neu beginnen?

Start-Codelab-App herunterladen

Die Start-App befindet sich im Verzeichnis material-components-flutter-codelabs-102-starter_and_101-complete/mdc_100_series.

...oder von GitHub klonen

Führen Sie die folgenden Befehle aus, um dieses Codelab von GitHub zu klonen:

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

Projekt öffnen und App ausführen

  1. Öffnen Sie das Projekt in einem Editor Ihrer Wahl.
  2. Folgen Sie der Anleitung zum Ausführen der App. unter Erste Schritte: Testlauf für den ausgewählten Editor.

Fertig! Auf deinem Gerät sollte nun die Shrine-Anmeldeseite aus dem MDC-101-Codelab angezeigt werden.

Android

iOS

Anmeldeseite mit Feldern für Nutzername und Passwort sowie den Schaltflächen „Abbrechen“ und „Weiter“

Anmeldeseite mit Feldern für Nutzername und Passwort sowie den Schaltflächen „Abbrechen“ und „Weiter“

Jetzt, da der Anmeldebildschirm gut aussieht, fügen wir einige Produkte in die App ein.

4. App-Leiste oben hinzufügen

Wenn Sie jetzt auf die Schaltfläche erscheint der Startbildschirm mit der Aufschrift "Du hast es geschafft!". Sehr gut. Jetzt haben die Nutzenden jedoch keine Aktionen mehr zu tun und sie haben auch kein Gefühl dafür, wo sie sich in der App befinden. Jetzt fügen wir die Navigation hinzu.

Material Design bietet Navigationsmuster, die ein hohes Maß an Nutzungsfreundlichkeit gewährleisten. Eine der sichtbarsten Komponenten ist die obere App-Leiste.

Fügen Sie eine obere App-Leiste hinzu, um die Navigation zu ermöglichen und Nutzern schnellen Zugriff auf andere Aktionen zu ermöglichen.

AppBar-Widget hinzufügen

Fügen Sie dem Gerüst in home.dart eine AppBar hinzu und entfernen Sie die hervorgehobene const:

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

Durch Hinzufügen der AppBar zum Feld appBar: des Scaffold erhalten wir kostenlos ein perfektes Layout, wobei die AppBar oben auf der Seite und der Text darunter platziert wird.

Text-Widget hinzufügen

Fügen Sie der AppBar in home.dart einen Titel hinzu:

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

Projekt speichern.

Android

iOS

App-Leiste mit dem Titel „Shrine“

App-Leiste mit dem Titel „Shrine“

Viele App-Leisten haben eine Schaltfläche neben dem Titel. Fügen wir unserer App ein Menüsymbol hinzu.

Vorangestellte IconButton hinzufügen

Legen Sie im Feld home.dart eine IconButton für das Feld leading: der AppBar fest. (Fügen Sie es vor das Feld title: ein, um die Reihenfolge von vorangestelltem zum letzten zu imitieren:)

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

Projekt speichern.

Android

iOS

Eine App-Leiste mit dem Titel „Schrein“ und einem Dreistrich-Menüsymbol

Eine App-Leiste mit dem Titel „Schrein“ und einem Dreistrich-Menüsymbol

Das Menüsymbol, auch „Hamburger“ genannt, wird genau dort angezeigt, wo Sie es erwarten würden.

Sie können auch am Ende des Titels Schaltflächen hinzufügen. In Flutter werden diese Aktionen als „Aktionen“ bezeichnet.

Aktionen hinzufügen

Du hast noch Platz für zwei weitere IconButtons.

Fügen Sie sie der AppBar-Instanz nach dem Titel hinzu:

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

Projekt speichern. Ihr Startbildschirm sollte nun so aussehen:

Android

iOS

eine App-Leiste mit dem Titel „Schrein“ und einem Symbol für das Dreistrich-Menü und die nachfolgende Suche und Anpassung von Symbolen

eine App-Leiste mit dem Titel „Schrein“ und einem Symbol für das Dreistrich-Menü und die nachfolgende Suche und Anpassung von Symbolen

Jetzt hat die App auf der rechten Seite eine Hauptschaltfläche, einen Titel und zwei Aktionen. In der App-Leiste wird außerdem Höhe mit einem dezenten Schatten angezeigt, der darauf hinweist, dass sich die Ebene auf einer anderen Ebene als der Inhalt befindet.

5. Karte in einem Raster hinzufügen

Unsere App hat jetzt eine gewisse Struktur. Organisieren Sie die Inhalte, indem Sie sie auf Karten platzieren.

Rasteransicht hinzufügen

Fügen wir zunächst eine Karte unter der oberen App-Leiste hinzu. Das Card-Widget allein verfügt nicht über genügend Informationen, um es dort anzuzeigen, wo wir es sehen können, daher sollten wir es in einem GridView-Widget kapseln.

Ersetzen Sie den Mittelpunkt im Textkörper des Scaffold durch eine Rasteransicht:

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

Entpacken wir diesen Code. GridView ruft den count()-Konstruktor auf, da die Anzahl der angezeigten Elemente zählbar und nicht unendlich ist. Es benötigt jedoch mehr Informationen, um das Layout zu definieren.

Mit crossAxisCount: wird angegeben, wie viele Elemente darin enthalten sind. Wir möchten zwei Spalten.

Das Feld padding: bietet Platz auf allen vier Seiten der Grid-Ansicht. Natürlich können Sie den Abstand am Ende oder am unteren Rand nicht sehen, da sich neben ihnen noch keine GridView-Unterelemente befinden.

Das Feld childAspectRatio: gibt die Größe der Elemente basierend auf einem Seitenverhältnis (Breite zu Höhe) an.

Standardmäßig erstellt GridView Kacheln, die alle die gleiche Größe haben.

Wir haben eine Karte, aber diese ist leer. Fügen wir unserer Karte nun untergeordnete Widgets hinzu.

Layout des Inhalts

Karten sollten Bereiche für ein Bild, einen Titel und Sekundärtext enthalten.

Aktualisieren Sie die untergeordneten Elemente von 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'),
            ],
          ),
        ),
      ],
    ),
  )
],

Mit diesem Code wird ein Spalten-Widget hinzugefügt, mit dem die untergeordneten Widgets vertikal angeordnet werden.

Das crossAxisAlignment: field gibt CrossAxisAlignment.start an, was bedeutet, dass der Text an der führenden Kante ausgerichtet wird.

Mit dem Widget AspectRatio wird festgelegt, welche Form das Bild unabhängig von der Art des übermittelten Bildes annimmt.

Durch das Abstanden wird der Text von der Seite ein wenig ein wenig eingefügt.

Die beiden Text-Widgets sind vertikal übereinander gestapelt. Dazwischen befinden sich acht freie Punkte (SizedBox). Wir erstellen eine weitere Column, um sie im Padding zu platzieren.

Projekt speichern.

Android

iOS

ein einzelnes Element mit einem Bild, einem Titel und einem Sekundärtext

ein einzelnes Element mit einem Bild, einem Titel und einem Sekundärtext

In dieser Vorschau sehen Sie, dass die Karte vom Rand eingesetzt ist, abgerundete Ecken hat und einen Schatten darstellt, der die Höhe der Karte zum Ausdruck bringt. Die gesamte Form wird als „Container“ bezeichnet. für Material. (Nicht zu verwechseln mit der Widget-Klasse Container).

Karten werden normalerweise zusammen mit anderen Karten in einer Sammlung angezeigt. Wir legen sie als Sammlung in einem Raster dar.

6. Kartensammlung erstellen

Wenn auf einem Bildschirm mehrere Karten angezeigt werden, werden sie in einer oder mehreren Sammlungen gruppiert. Karten in einer Sammlung sind koplanar, d. h. Karten haben dieselbe Ruhehöhe wie andere Karten (es sei denn, die Karten werden aufgenommen oder gezogen, das wird hier jedoch nicht passieren).

Karte in eine Sammlung multiplizieren

Im Moment wird unsere Karte inline im Feld children: von GridView erstellt. Das ist eine Menge verschachtelter Code, der möglicherweise schwer zu lesen ist. Wir extrahieren ihn in eine Funktion, die beliebig viele leere Karten generieren kann und eine Liste mit Karten zurückgibt.

Erstellen Sie eine neue private Funktion über der Funktion build(). Funktionen, die mit einem Unterstrich beginnen, sind private APIs:

// 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;
}

Weisen Sie die generierten Karten dem Feld children von GridView zu. Denken Sie daran, alle in GridView enthaltenen Elemente durch diesen neuen Code zu ersetzen:

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

Projekt speichern.

Android

iOS

Ein Raster von Elementen mit einem Bild, einem Titel und einem Sekundärtext

Ein Raster von Elementen mit einem Bild, einem Titel und einem Sekundärtext

Die Karten sind zwar vorhanden, aber es wird noch nichts angezeigt. Jetzt ist es an der Zeit, Produktdaten hinzuzufügen.

Produktdaten hinzufügen

Die App enthält einige Produkte mit Bildern, Namen und Preisen. Fügen wir das zu den Widgets hinzu, die bereits auf der Karte vorhanden sind.

Importieren Sie dann in home.dart ein neues Paket und einige Dateien, die wir für ein Datenmodell bereitgestellt haben:

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

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

Ändern Sie abschließend _buildGridCards(), um die Produktinformationen abzurufen, und verwenden Sie diese Daten in den Karten:

// 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();
}

HINWEIS:Wird noch nicht kompiliert und ausgeführt. Es gibt noch eine weitere Änderung.

Ändern Sie außerdem die Funktion build(), damit BuildContext an _buildGridCards() übergeben wird, bevor Sie versuchen, einen Kompilierungsvorgang auszuführen:

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

Starten Sie die App noch einmal neu.

Android

iOS

Ein Raster von Artikeln mit einem Bild, einem Produkttitel und einem Preis

Ein Raster von Artikeln mit einem Bild, einem Produkttitel und einem Preis

Wie Sie möglicherweise feststellen, ist zwischen den Karten kein vertikaler Abstand. Das liegt daran, dass sie standardmäßig 4 Randpunkte oben und unten haben.

Projekt speichern.

Die Produktdaten werden angezeigt, aber die Bilder haben zusätzlichen Platz um sie herum. Die Bilder werden standardmäßig mit einem BoxFit von .scaleDown gezeichnet (in diesem Fall). Ändern wir dies in .fitWidth, damit sie etwas heranzoomen und den zusätzlichen Leerraum entfernen.

Fügen Sie dem Bild das Feld fit: mit dem Wert BoxFit.fitWidth hinzu:

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

Android

iOS

Ein Raster von Artikeln mit einem zugeschnittenen Bild, einem Produkttitel und einem Preis

Unsere Produkte werden jetzt perfekt in der App angezeigt.

7. Glückwunsch!

Unsere App hat einen grundlegenden Ablauf, der den Nutzer vom Anmeldebildschirm zu einem Startbildschirm bringt, auf dem die Produkte angezeigt werden können. Mit nur wenigen Codezeilen fügten wir eine obere App-Leiste (mit einem Titel und drei Schaltflächen) und Karten für die Präsentation des App-Inhalts hinzu. Unser Startbildschirm ist jetzt einfach und funktional, mit einer grundlegenden Struktur und umsetzbaren Inhalten.

Weiteres Vorgehen

Mit der oberen App-Leiste, der Karte, dem Textfeld und der Schaltfläche haben wir jetzt vier Kernkomponenten aus der Material Flutter-Bibliothek verwendet. Weitere Informationen finden Sie im Katalog der Materialkomponenten-Widgets.

Unsere App ist zwar voll funktionsfähig, drückt aber noch keine bestimmte Marke oder einen bestimmten Standpunkt aus. In MDC-103: Material Design Theming with Color, Shape, Elevation and Type passen wir den Stil dieser Komponenten an, um eine lebendige, moderne Marke auszudrücken.

Ich konnte dieses Codelab mit angemessenem Zeit- und Arbeitsaufwand abschließen

<ph type="x-smartling-placeholder"></ph> Stimme vollkommen zu Stimme zu Weder zufrieden noch unzufrieden Stimme nicht zu Stimme überhaupt nicht zu

Ich möchte Material Components weiterhin verwenden.

<ph type="x-smartling-placeholder"></ph> Stimme vollkommen zu Stimme zu Weder zufrieden noch unzufrieden Stimme nicht zu Stimme überhaupt nicht zu