Store: The Product Grid
Part of the Projects section of Coddy's Flutter journey. Lesson 19 of 36.
The third app is a small store: a grid of products, a page for each one, a cart and a checkout. It is the shape of most shopping apps, and it brings back Provider and intl.
The products are in the starter, each with a name, a price, an icon, a color and a description. A store shows them in a grid, two to a row on a phone:
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)],
)childAspectRatio is width divided by height: 0.8 makes each card a little taller than wide, room for a picture and two lines of text.
Each card is its own widget, ProductCard, that takes a Product. Inside, an Expanded tile fills the space above the name. Its color is the lightest shade of the product's color, product.color.shade50, with the icon in the full color on top. That is why color is a MaterialColor: it has the shades.
Challenge
MediumShow the products:
- write a
ProductCardwidget that takes arequiredproduct - it is a
Card(withclipBehavior: Clip.antiAlias) holding aColumn: anExpandedfull-widthContainerinproduct.color.shade50with the product's icon in the middle (size 56,product.color), then the name intitleMediumwith 12 pixels of padding - replace the
Centerwith theGridView.countfrom the theory
Try it yourself
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
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: const Center(
child: Text('Products go here'),
),
);
}
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Projects
3Project: Store
Store: The Product GridStore: PricesPractice on your own: Online Flutter compiler