Shop: Produktdetails
Teil des Abschnitts Projekte der Flutter-Journey von Coddy. Lektion 21 von 36.
Tippe in einem Geschäft auf ein Produkt, und seine Seite wird angezeigt: ein großes Bild, der Preis und ein paar Worte dazu. Das ist ein zweiter Bildschirm, ProductScreen, der das Produkt über seinen Konstruktor erhält.
Damit die ganze Karte antippbar ist, platziere ein InkWell innerhalb der Card um ihren Inhalt herum. Es führt onTap aus und zeichnet den Welleneffekt, den du in Material-Apps siehst; das Clip.antiAlias der Karte hält den Welleneffekt innerhalb der abgerundeten Ecken.
Card(
clipBehavior: Clip.antiAlias,
child: InkWell(
onTap: () {
Navigator.push(context, MaterialPageRoute(
builder: (context) => ProductScreen(product: product),
));
},
child: Column(...),
),
)Die Produktseite ist eine ListView, sodass eine lange Beschreibung scrollbar ist. Ihre AppBar zeigt den Namen des Produkts und den Zurück-Pfeil, den Flutter automatisch für dich auf einem weitergeleiteten Bildschirm hinzufügt.
Für den großen Preis nimm den Stil headlineSmall des Designs und ändere mit copyWith nur, was du brauchst: textTheme.headlineSmall?.copyWith(fontWeight: FontWeight.bold). Das ?. steht dort, weil ein Designstil null sein kann.
Aufgabe
MittelGib jedem Produkt eine eigene Seite:
- Schreibe einen
ProductScreen, der einrequiredproductentgegennimmt, wobei der Name in derAppBarangezeigt wird - Der Inhalt besteht aus einer
ListViewmit 24 Pixeln Innenabstand: einer 240 Pixel hohen Kachel inproduct.color.shade50mit Eckenradius 24 und dem Icon in Größe 120, dann 24 Pixel Abstand, dem Preis (headlineSmallin Fettschrift und in der Primärfarbe), 12 Pixel Abstand und der Beschreibung inbodyLarge - Umschließe die
Columnjeder Karte mit einemInkWell, der zur Produktseite navigiert
Probier es selbst
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
void main() {
runApp(const MyApp());
}
final money = NumberFormat.currency(locale: 'en_US', symbol: '\$');
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.orange),
),
home: const ShopScreen(),
);
}
}
class Product {
const Product({
required this.name,
required this.price,
required this.icon,
required this.color,
required this.description,
});
final String name;
final double price;
final IconData icon;
final MaterialColor color;
final String description;
}
const List<Product> products = [
Product(
name: 'Headphones',
price: 59,
icon: Icons.headphones,
color: Colors.indigo,
description: 'Wireless headphones with 30 hours of battery.',
),
Product(
name: 'Watch',
price: 129,
icon: Icons.watch,
color: Colors.teal,
description: 'A smart watch that counts your steps.',
),
Product(
name: 'Backpack',
price: 45.5,
icon: Icons.backpack,
color: Colors.orange,
description: 'Room for a laptop, a lunch and a jacket.',
),
Product(
name: 'Mug',
price: 12,
icon: Icons.coffee,
color: Colors.brown,
description: 'Holds a big coffee and keeps it warm.',
),
Product(
name: 'Camera',
price: 1299,
icon: Icons.photo_camera,
color: Colors.blueGrey,
description: 'A mirrorless camera for sharp photos.',
),
Product(
name: 'Sneakers',
price: 89.99,
icon: Icons.directions_run,
color: Colors.red,
description: 'Light running shoes for every day.',
),
];
class ShopScreen extends StatelessWidget {
const ShopScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Coddy Shop')),
body: GridView.count(
crossAxisCount: 2,
padding: const EdgeInsets.all(16),
mainAxisSpacing: 12,
crossAxisSpacing: 12,
childAspectRatio: 0.8,
children: [
for (Product product in products) ProductCard(product: product),
],
),
);
}
}
class ProductCard extends StatelessWidget {
const ProductCard({super.key, required this.product});
final Product product;
@override
Widget build(BuildContext context) {
return Card(
clipBehavior: Clip.antiAlias,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Container(
width: double.infinity,
alignment: Alignment.center,
color: product.color.shade50,
child: Icon(product.icon, size: 56, color: product.color),
),
),
Padding(
padding: const EdgeInsets.all(12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
product.name,
style: Theme.of(context).textTheme.titleMedium,
),
const SizedBox(height: 4),
Text(
money.format(product.price),
style: TextStyle(
fontWeight: FontWeight.bold,
color: Theme.of(context).colorScheme.primary,
),
),
],
),
),
],
),
);
}
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Projekte
1Projekt: To-do-Liste
To-do-Liste: Die AufgabenlisteTo-do-Liste: Eine Aufgabe hinzufügen4Projekt: Gewohnheitstracker
Gewohnheitstracker: Deine GewohnheitenGewohnheitstracker: Die WocheÜbe selbstständig: Online-Flutter-Compiler