DEV Community

Cover image for Panduan Praktikum Flutter: Membuat Halaman Daftar dan Detail Produk dengan Data Dummy dan UI Modern
ahmadasroni38
ahmadasroni38

Posted on

Panduan Praktikum Flutter: Membuat Halaman Daftar dan Detail Produk dengan Data Dummy dan UI Modern

Berikut adalah versi praktikum lengkap untuk membuat Halaman List Product dan Halaman Detail Product menggunakan Flutter terbaru. Modul ini menggunakan data dummy tanpa API service untuk kemudahan implementasi, dengan struktur yang terorganisir dan UI yang modern.


Package yang Perlu Diinstall

Untuk memulai, pastikan Flutter terbaru telah diinstal. Tambahkan package berikut jika diperlukan:

  1. flutter_screenutil (untuk responsivitas)
  2. google_fonts (untuk font yang lebih baik)
  3. flutter_svg (jika Anda ingin menggunakan file SVG untuk ikon)

Perintah untuk menginstall:

flutter pub add flutter_screenutil google_fonts flutter_svg
Enter fullscreen mode Exit fullscreen mode

Struktur Folder Proyek

lib/
├── models/
│   ├── product.dart
├── screens/
│   ├── product_list_screen.dart
│   ├── product_detail_screen.dart
├── widgets/
│   ├── product_card.dart
├── main.dart
Enter fullscreen mode Exit fullscreen mode

1. Model Produk (product.dart)

dart name=lib/models/product.dart
class Product {
  final int id;
  final String name;
  final String description;
  final double price;
  final String imageUrl;

  Product({
    required this.id,
    required this.name,
    required this.description,
    required this.price,
    required this.imageUrl,
  });
}
Enter fullscreen mode Exit fullscreen mode

2. Dummy Data Produk

Tambahkan data dummy langsung di file product_list_screen.dart.


3. Widget Kartu Produk (product_card.dart)

import 'package:flutter/material.dart';
import '../models/product.dart';

class ProductCard extends StatelessWidget {
  final Product product;
  final VoidCallback onTap;

  const ProductCard({
    Key? key,
    required this.product,
    required this.onTap,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: onTap,
      child: Container(
        decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(15),
            gradient: const LinearGradient(
              colors: [Color(0xFFF6F6F6), Color(0xFFEFEFEF)],
              begin: Alignment.topLeft,
              end: Alignment.bottomRight,
            ),
            boxShadow: [
              BoxShadow(
                color: Colors.black.withOpacity(0.1),
                blurRadius: 10,
                offset: const Offset(0, 5),
              ),
            ],
            border: Border.all(
              color: Colors.grey.shade300,
              width: 1,
            )),
        child: LayoutBuilder(
          builder: (context, constraints) {
            return Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                // Image Section with fixed aspect ratio
                ClipRRect(
                  borderRadius: const BorderRadius.vertical(
                    top: Radius.circular(15),
                  ),
                  child: SizedBox(
                    width: constraints.maxWidth,
                    height: 250, // Makes it square
                    child: Image.network(
                      product.imageUrl,
                      fit: BoxFit.cover,
                      loadingBuilder: (context, child, loadingProgress) {
                        if (loadingProgress == null) return child;
                        return Center(
                          child: CircularProgressIndicator(
                            value: loadingProgress.expectedTotalBytes != null
                                ? loadingProgress.cumulativeBytesLoaded /
                                    loadingProgress.expectedTotalBytes!
                                : null,
                          ),
                        );
                      },
                      errorBuilder: (context, error, stackTrace) {
                        return const Center(
                          child: Icon(
                            Icons.broken_image,
                            size: 50,
                            color: Colors.grey,
                          ),
                        );
                      },
                    ),
                  ),
                ),
                // Product Info Section
                Padding(
                  padding: const EdgeInsets.all(12.0),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      // Product Name
                      SizedBox(
                        width: constraints.maxWidth - 24, // Account for padding
                        child: Text(
                          product.name,
                          maxLines: 1,
                          overflow: TextOverflow.ellipsis,
                          style:
                              Theme.of(context).textTheme.headline6?.copyWith(
                                    fontSize: 16,
                                    fontWeight: FontWeight.bold,
                                  ),
                        ),
                      ),
                      const SizedBox(height: 4),
                      // Product Price
                      Text(
                        '\$${product.price.toStringAsFixed(2)}',
                        style: const TextStyle(
                          fontSize: 14,
                          color: Colors.green,
                          fontWeight: FontWeight.w600,
                        ),
                      ),
                      const SizedBox(height: 8),
                      // Action Buttons
                      Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        children: [
                          Flexible(
                            child: ElevatedButton(
                              onPressed: onTap,
                              style: ElevatedButton.styleFrom(
                                backgroundColor: Colors.blueAccent,
                                shape: RoundedRectangleBorder(
                                  borderRadius: BorderRadius.circular(8),
                                ),
                                minimumSize: const Size(0, 36), // Fixed height
                              ),
                              child: const FittedBox(
                                child: Text(
                                  "View Details",
                                  style: TextStyle(fontSize: 12),
                                ),
                              ),
                            ),
                          ),
                          IconButton(
                            onPressed: () {
                              // Add to cart action
                            },
                            icon: const Icon(Icons.shopping_cart_outlined),
                            color: Colors.black54,
                            padding: EdgeInsets.zero, // Remove default padding
                            constraints: const BoxConstraints(
                              maxWidth: 40,
                              maxHeight: 40,
                            ),
                          ),
                        ],
                      ),
                    ],
                  ),
                ),
              ],
            );
          },
        ),
      ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

4. Halaman Daftar Produk (product_list_screen.dart)

dart name=lib/screens/product_list_screen.dart
import 'package:flutter/material.dart';
import '../models/product.dart';
import '../widgets/product_card.dart';
import 'product_detail_screen.dart';

class ProductListScreen extends StatelessWidget {
  ProductListScreen({Key? key}) : super(key: key);

  // Dummy data
  final List<Product> products = [
    Product(
      id: 1,
      name: 'Wireless Headphones',
      description: 'High-quality wireless headphones with noise cancellation.',
      price: 99.99,
      imageUrl: 'https://via.placeholder.com/150',
    ),
    Product(
      id: 2,
      name: 'Smart Watch',
      description: 'Keep track of your health and notifications.',
      price: 199.99,
      imageUrl: 'https://via.placeholder.com/150',
    ),
    Product(
      id: 3,
      name: 'Gaming Mouse',
      description: 'Ergonomic design with customizable buttons.',
      price: 49.99,
      imageUrl: 'https://via.placeholder.com/150',
    ),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Product List'),
        centerTitle: true,
      ),
      body: GridView.builder(
        padding: const EdgeInsets.all(10),
        gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 2,
          crossAxisSpacing: 10,
          mainAxisSpacing: 10,
        ),
        itemCount: products.length,
        itemBuilder: (context, index) {
          return ProductCard(
            product: products[index],
            onTap: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => ProductDetailScreen(product: products[index]),
                ),
              );
            },
          );
        },
      ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

5. Halaman Detail Produk (product_detail_screen.dart)

dart name=lib/screens/product_detail_screen.dart
import 'package:flutter/material.dart';
import '../models/product.dart';

class ProductDetailScreen extends StatelessWidget {
  final Product product;

  const ProductDetailScreen({Key? key, required this.product}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(product.name),
        centerTitle: true,
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Image.network(
              product.imageUrl,
              height: 200,
              width: double.infinity,
              fit: BoxFit.cover,
            ),
            const SizedBox(height: 20),
            Text(
              product.name,
              style: const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
            ),
            const SizedBox(height: 10),
            Text(
              '\$${product.price.toStringAsFixed(2)}',
              style: const TextStyle(fontSize: 20, color: Colors.green),
            ),
            const SizedBox(height: 20),
            Text(
              product.description,
              style: const TextStyle(fontSize: 16),
            ),
          ],
        ),
      ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

6. Main File (main.dart)

dart name=lib/main.dart
import 'package:flutter/material.dart';
import 'screens/product_list_screen.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Product App',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: ProductListScreen(),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

Penjelasan

  1. Arsitektur Modular:

    • Folder models untuk model data.
    • Folder screens untuk tampilan halaman.
    • Folder widgets untuk komponen UI yang dapat digunakan kembali.
  2. UI Modern:

    • GridView untuk menampilkan produk dalam bentuk grid.
    • Card widget untuk menampilkan setiap produk dengan gambar, nama, dan harga.
  3. Navigasi:

    • Menggunakan Navigator untuk berpindah antar halaman.
  4. Paket Tambahan:

    • flutter_screenutil untuk responsivitas (opsional).
    • google_fonts untuk gaya font yang lebih menarik (opsional).
  5. Dummy Data:

    • Data dummy digunakan langsung di widget untuk menyederhanakan praktikum tanpa API.

Dengan modul ini, Anda dapat mempelajari dasar-dasar Flutter untuk membuat aplikasi yang terstruktur dan mudah dikembangkan. Anda dapat menambahkan fitur lebih lanjut seperti filter produk atau integrasi API di masa mendatang.

Top comments (0)