Boutique : les détails du produit
Fait partie de la section Projets du Journey Flutter de Coddy. Leçon 21 sur 36.
Touchez un produit dans un magasin et vous accédez à sa page : une grande image, le prix et quelques mots à son sujet. C’est un deuxième écran, ProductScreen, qui reçoit le produit via son constructeur.
Pour rendre toute une carte cliquable, placez un InkWell à l’intérieur du Card, autour de son contenu. Il exécute onTap et dessine l’ondulation que vous voyez dans les applications Material ; le Clip.antiAlias de la carte maintient l’ondulation à l’intérieur des coins arrondis.
Card(
clipBehavior: Clip.antiAlias,
child: InkWell(
onTap: () {
Navigator.push(context, MaterialPageRoute(
builder: (context) => ProductScreen(product: product),
));
},
child: Column(...),
),
)La page du produit est une ListView, ce qui permet de faire défiler une longue description. Son AppBar affiche le nom du produit et la flèche de retour, que Flutter ajoute pour vous lorsqu’un écran est ouvert par navigation.
Pour afficher le grand prix, partez de headlineSmall du thème et ne modifiez que ce dont vous avez besoin avec copyWith : textTheme.headlineSmall?.copyWith(fontWeight: FontWeight.bold). Le ?. est là parce qu’un style de thème peut être null.
Défi
MoyenAttribue une page à chaque produit :
- écris un
ProductScreenqui prend unrequiredproduct, avec le nom dans sonAppBar - son corps est un
ListViewavec une marge intérieure de 24 pixels : une tuile de 240 pixels de haut enproduct.color.shade50, avec des coins arrondis de 24 pixels et l’icône de taille 120, puis 24 pixels, le prix (enheadlineSmallgras et dans la couleur principale), 12 pixels et la description enbodyLarge - entoure la
Columnde chaque carte avec unInkWellqui ouvre la page du produit
Essayez vous-même
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,
),
),
],
),
),
],
),
);
}
}
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Projets
1Projet : Liste de tâches
Liste de tâches : La liste des tâchesListe de tâches : Ajouter une tâche4Projet : Suivi des habitudes
Suivi des habitudes : Vos habitudesSuivi des habitudes : La semaineEntraînez-vous par vous-même : Compilateur Flutter en ligne