Menu
CoddyTech

Магазин: сетка товаров

Часть раздела Проекты путешествия по Flutter на Coddy. Урок 19 из 36.

Третье приложение — небольшой магазин: сетка товаров, страница для каждого товара, корзина и оформление заказа. Так устроено большинство приложений для покупок, и здесь снова используется Provider и intl.

Товары уже есть в начальном проекте; у каждого есть название, цена, значок, цвет и описание. Магазин показывает их в сетке — по два товара в ряд на телефоне:

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 — это отношение ширины к высоте: значение 0.8 делает каждую карточку немного выше, чем шире, оставляя место для изображения и двух строк текста.

Каждая карточка — отдельный виджет ProductCard, которому передаётся Product. Внутри плитка Expanded заполняет пространство над названием. Её цвет — самый светлый оттенок цвета товара, product.color.shade50, а сверху размещён значок основного цвета. Поэтому color имеет тип MaterialColor: у него есть оттенки.

challenge icon

Задание

Средне

Покажи товары:

  • напиши виджет ProductCard, который принимает обязательный параметр product
  • это Card (с clipBehavior: Clip.antiAlias), содержащая Column: полноширинный Container внутри Expanded, окрашенный в product.color.shade50, с иконкой товара по центру (размер 56, product.color), затем название в titleMedium с отступом 12 пикселей
  • замени Center на GridView.count из теоретической части

Попробуйте сами

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'),
      ),
    );
  }
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Проекты

Потренируйтесь самостоятельно: Онлайн-компилятор Flutter