Menu
CoddyTech

Mağaza: Ürün Ayrıntıları

Coddy'nin Flutter Journey'sinin Projeler bölümünün bir parçası. Ders 21 / 36.

Bir mağazada bir ürüne dokunduğunda ürünün sayfası açılır: büyük bir resim, fiyatı ve ürün hakkında birkaç kelime. Bu, ürünü kurucusu aracılığıyla alan ikinci bir ekrandır: ProductScreen.

Bir kartın tamamını dokunulabilir yapmak için içeriğinin çevresine, Card içine bir InkWell yerleştir. Bu, onTap işlevini çalıştırır ve Material uygulamalarında gördüğün dalgalanma efektini çizer; kartın Clip.antiAlias özelliği, dalgalanma efektini yuvarlatılmış köşelerin içinde tutar.

Card(
  clipBehavior: Clip.antiAlias,
  child: InkWell(
    onTap: () {
      Navigator.push(context, MaterialPageRoute(
        builder: (context) => ProductScreen(product: product),
      ));
    },
    child: Column(...),
  ),
)

Ürün sayfası bir ListView olduğundan uzun bir açıklama kaydırılabilir. AppBar ürünün adını ve Flutter'ın açılan bir ekranda senin için eklediği geri okunu gösterir.

Büyük fiyatı biçimlendirmek için temanın headlineSmall stilinden başla ve yalnızca gerekenleri copyWith ile değiştir: textTheme.headlineSmall?.copyWith(fontWeight: FontWeight.bold). Tema stili null olabileceğinden ?. kullanılır.

challenge icon

Görev

Orta

Her ürüne bir sayfa verin:

  • required product parametresini alan ve adını AppBar içinde gösteren bir ProductScreen yazın
  • gövdesi, 24 piksellik dolgusu olan bir ListView olsun: product.color.shade50 renginde, 240 piksel yüksekliğinde, köşeleri 24 piksel yuvarlatılmış ve simgesi 120 boyutunda bir kutu; ardından 24 piksel boşluk, fiyat (birincil renkte kalın headlineSmall), 12 piksel boşluk ve bodyLarge biçiminde açıklama
  • her kartın Column bileşenini, ürünün sayfasına yönlendiren bir InkWell ile sarın

Kendin dene

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,
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}
quiz iconKendini test et

Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.

Projeler bölümündeki tüm dersler

Kendi başına pratik yap: Online Flutter derleyicisi