1. Einführung
Mit Material Components (MDC) können Entwickler Material Design implementieren. MDC wurde von einem Team von Entwicklern und UX-Designern bei Google entwickelt und bietet Dutzende ansprechender und funktionaler UI-Komponenten. Es ist für Android, iOS, Web und Flutter verfügbar.material.io/develop |
Im Codelab MDC-101 haben Sie zwei Materialkomponenten verwendet, um eine Anmeldeseite zu erstellen: Textfelder und Schaltflächen mit Tintenwellen. Erweitern wir diese Grundlage nun um Navigation, Struktur und Daten.
Umfang
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:
- Obere App-Leiste
- Eine Produktrasterliste
Android | iOS |
Codelab: Material Flutter-Komponenten und -Subsysteme
- Obere App-Leiste
- Raster
- Karten
Wie würden Sie Ihre Erfahrung mit der Flutter-Entwicklung bewerten?
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 einem der folgenden 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)
- Einen Browser (für die Fehlerbehebung ist Chrome erforderlich)
- Als Windows-, Linux- oder macOS-Desktopanwendung Sie müssen die Entwicklung auf der Plattform durchführen, auf der Sie die Bereitstellung planen. Wenn Sie also eine Windows-Desktopanwendung entwickeln möchten, müssen Sie die Entwicklung unter Windows durchführen, um auf die entsprechende Build-Kette zugreifen zu können. Es gibt betriebssystemspezifische Anforderungen, die unter docs.flutter.dev/desktop ausführlich beschrieben werden.
3. Codelab-Starter-App herunterladen
Sind Sie nach MDC-101 weitergegangen?
Wenn Sie MDC-101 abgeschlossen haben, sollte Ihr Code für dieses Codelab bereit sein. Fahren Sie mit dem Schritt Obene App-Leiste hinzufügen fort.
Sie beginnen ganz neu?
Start-Codelab-App herunterladen
Die Start-App befindet sich im Verzeichnis material-components-flutter-codelabs-102-starter_and_101-complete/mdc_100_series
.
…oder es aus 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
- Öffnen Sie das Projekt in einem Editor Ihrer Wahl.
- 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 |
Jetzt, da der Anmeldebildschirm gut aussieht, fügen wir einige Produkte in die App ein.
4. App-Leiste oben hinzufügen
Wenn Sie derzeit auf die Schaltfläche „Weiter“ klicken, wird der Startbildschirm mit der Meldung „Du hast es geschafft!“ angezeigt. Sehr gut. Jetzt kann der Nutzer aber nichts tun und hat keine Ahnung, wo er sich in der App befindet. Daher ist es an der Zeit, eine Navigation hinzuzufügen.
Material Design bietet Navigationsmuster, die ein hohes Maß an Nutzungsfreundlichkeit gewährleisten. Eine der am besten sichtbaren Komponenten ist eine App-Leiste oben.
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 in home.dart
dem Scaffold eine AppBar hinzu und entfernen Sie das hervorgehobene const
:
return const Scaffold(
// TODO: Add app bar (102)
appBar: AppBar(
// TODO: Add buttons and title (102)
),
Wenn wir die AppBar dem Feld appBar:
des Scaffolds hinzufügen, erhalten wir kostenlos ein perfektes Layout, bei dem die AppBar oben auf der Seite und der Body darunter bleibt.
Text-Widget hinzufügen
Fügen Sie in home.dart
einen Titel zur App-Leiste 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 |
Viele App-Leisten haben neben dem Titel eine Schaltfläche. 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 |
Das Dreistrich-Menü (auch als „Dreistrich-Menü“ bezeichnet) wird genau dort angezeigt, wo Sie es erwarten würden.
Sie können dem Titel auch Schaltflächen hinzufügen. In Flutter werden diese als „Aktionen“ bezeichnet.
Aktionen hinzufügen
Es ist Platz für zwei weitere Symbolschaltflächen.
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 so aussehen:
Android | iOS |
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
Jetzt, da unsere App eine gewisse Struktur hat, können wir die Inhalte organisieren, indem wir sie auf Karten platzieren.
GridView hinzufügen
Fügen Sie zuerst 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()],
),
Sehen wir uns diesen Code an. GridView ruft den count()
-Konstruktor auf, da die Anzahl der angezeigten Elemente zählbar und nicht unendlich ist. Für die Definition des Layouts sind jedoch weitere Informationen erforderlich.
Mit crossAxisCount:
wird angegeben, wie viele Elemente quer angezeigt werden sollen. 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ären Text haben.
Aktualisieren Sie die untergeordneten Elemente der 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.
Die crossAxisAlignment: field
gibt CrossAxisAlignment.start
an, was bedeutet, dass der Text an der Vorderkante ausgerichtet werden soll.
Das Widget Seitenverhältnis bestimmt die Form des Bildes, unabhängig von der Art des Bildes.
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 Spalte, um sie im Padding unterzubringen.
Projekt speichern.
Android | iOS |
In dieser Vorschau sehen Sie, dass die Karte vom Rand aus platziert ist, abgerundete Ecken hat und einen Schatten darstellt, der die Höhe der Karte zum Ausdruck bringt. Die gesamte Form wird in Material als „Container“ bezeichnet. Nicht zu verwechseln mit der Widget-Klasse Container.
Karten werden normalerweise zusammen mit anderen Karten in einer Sammlung angezeigt. Legen Sie sie als Sammlung in einem Raster an.
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 gemacht).
Karte in einer Sammlung vervielfachen
Derzeit wird unsere Karte inline im Feld children:
der GridView erstellt. Das ist viel verschachtelter Code, der schwer zu lesen sein kann. Wir extrahieren es in eine Funktion, die beliebig viele leere Karten generieren und eine Liste von Karten zurückgeben kann.
Erstellen Sie über der Funktion build()
eine neue private Funktion. Denken Sie daran, dass Funktionen, die mit einem Unterstrich beginnen, zu privaten APIs gehören:
// 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
der 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 |
Die Karten sind 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 den Widgets hinzu, die wir bereits auf der Karte haben.
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()
so, dass die Produktinformationen abgerufen und in den Karten verwendet werden:
// 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 |
Wie Sie sehen, haben wir zwischen den Karten keinen vertikalen Abstand hinzugefügt. 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 in diesem Fall standardmäßig mit einem BoxFit von .scaleDown
gezeichnet. Ändern wir das in .fitWidth
, damit sie etwas herangezoomt werden und die zusätzlichen Leerzeichen entfernt werden.
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 |
Unsere Produkte werden jetzt perfekt in der App angezeigt.
7. Glückwunsch!
Unsere App hat einen einfachen Ablauf, bei dem Nutzer vom Anmeldebildschirm zu einem Startbildschirm weitergeleitet werden, auf dem Produkte angezeigt werden. 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 Hauptkomponenten aus der Material Flutter-Bibliothek verwendet. Weitere Informationen finden Sie im Katalog der Material Components-Widgets.
Die App ist zwar voll funktionsfähig, repräsentiert aber noch keine bestimmte Marke oder einen bestimmten Standpunkt. 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.