Learn how to build a product list app in Flutter using HTTP requests to fetch data, displaying product cards with images, titles, prices, and discounts. Explore different layouts like ListView and GridView, and enhance the app with rounded corners and discount badges. This beginner-friendly tutorial will guide you through the process of creating a dynamic and visually appealing product list for your Flutter applications.
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Product List Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<dynamic> _products = [];
@override
void initState() {
super.initState();
fetchProducts();
}
Future<void> fetchProducts() async {
var url = Uri.parse('https://dummyjson.com/products');
var response = await http.get(url);
setState(() {
if (response.statusCode == 200) {
// Successful request
var data = json.decode(response.body);
_products = data['products'];
} else {
// Request failed
_products = [];
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Product List'),
),
body: GridView.builder(
padding: EdgeInsets.all(8),
itemCount: _products.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
childAspectRatio: 0.7,
),
itemBuilder: (context, index) {
var product = _products[index];
var thumbnailUrl = product['thumbnail'];
var discount = product['discountPercentage'];
return Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10),
),
elevation: 4,
child: Column(
children: [
Expanded(
flex: 3,
child: Stack(
children: [
ClipRRect(
borderRadius: BorderRadius.vertical(
top: Radius.circular(10),
),
child: Image.network(
thumbnailUrl,
width: double.infinity,
fit: BoxFit.cover,
),
),
if (discount != null)
Positioned(
top: 8,
right: 8,
child: Container(
padding: EdgeInsets.symmetric(
vertical: 4,
horizontal: 8,
),
decoration: BoxDecoration(
color: Colors.red,
borderRadius: BorderRadius.circular(8),
),
child: Text(
'${discount.toStringAsFixed(2)}% OFF',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 12,
),
),
),
),
],
),
),
Expanded(
flex: 2,
child: ListTile(
title: Text(
product['title'],
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
subtitle: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Price: \$${product['price']}'),
if (discount != null)
Text('Discount: ${discount.toStringAsFixed(2)}%'),
if (product['stock'] == 0)
Text(
'Out of Stock',
style: TextStyle(
color: Colors.red,
),
),
],
),
),
),
],
),
);
},
),
);
}
}
In this updated code, a Card widget is used to wrap each product, and the Card is given rounded corners using the borderRadius
property. The product image is displayed using the Image.network
widget within a ClipRRect to achieve rounded top corners. If the product has a discount, a Positioned widget is used to place a Container with the discount text as a badge on the top right corner of the image.
You can run this code in a Flutter project to see the list of products fetched from the API displayed in a Card format, with rounded corners and the discount badge displayed on top of the product image.