Flutter 商城商品详情页添加购物车和数量选择功能
为了添加购物车和数量选择,需要在 _buildProductDetail 方法里面添加一个 Column,里面包含一个 Row 和一个 ElevatedButton。Row 包含数量选择和添加到购物车按钮,ElevatedButton 用来显示购物车商品数量和跳转到购物车页面。代码如下:
Widget _buildProductDetail(Product product) {
int quantity = 1;
return SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
CachedNetworkImage(
imageUrl: product.imageUrl,
fit: BoxFit.cover,
errorWidget: (context, url, error) => Icon(Icons.error),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
product.name,
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
),
SizedBox(height: 8),
Text(
'价格: ¥${product.price.toStringAsFixed(2)}',
style: TextStyle(fontSize: 18),
),
SizedBox(height: 8),
Text(
'品牌: ${product.brand}',
style: TextStyle(fontSize: 18),
),
SizedBox(height: 8),
Text(
'描述: ${product.description}',
style: TextStyle(fontSize: 18),
),
SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
IconButton(
icon: Icon(Icons.remove),
onPressed: () {
setState(() {
quantity = quantity > 1 ? quantity - 1 : 1;
});
},
),
Text(
quantity.toString(),
style: TextStyle(fontSize: 18),
),
IconButton(
icon: Icon(Icons.add),
onPressed: () {
setState(() {
quantity++;
});
},
),
],
),
ElevatedButton(
onPressed: () async {
String url =
'http://book.musecloud.tech/addcart?productId=${product.id}&quantity=$quantity';
Response response = await _dio.get(url);
if (response.data == 'success') {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('添加到购物车成功'),
duration: Duration(seconds: 2),
),
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('添加到购物车失败,请稍后重试'),
duration: Duration(seconds: 2),
),
);
}
},
child: Text('添加到购物车'),
),
],
),
SizedBox(height: 16),
ElevatedButton(
onPressed: () {
// TODO: 跳转到购物车页面
},
child: FutureBuilder<List<dynamic>>(
future: ApiService.getShoppingCart(),
builder: (context, snapshot) {
if (snapshot.hasData) {
int count = snapshot.data![1].length;
return Row(
children: [
Icon(Icons.shopping_cart),
SizedBox(width: 8),
Text('购物车($count)'),
],
);
} else {
return Row(
children: [
Icon(Icons.shopping_cart),
SizedBox(width: 8),
Text('购物车'),
],
);
}
},
),
),
],
),
),
],
),
);
}
购物车展示的部分可以用一个 BottomSheet 实现,长按按钮展示,代码如下:
GestureDetector(
onLongPress: () {
showModalBottomSheet(
context: context,
builder: (context) {
return FutureBuilder<List<dynamic>>(
future: ApiService.getShoppingCart(),
builder: (context, snapshot) {
if (snapshot.hasData) {
List<dynamic> data = snapshot.data!;
List<dynamic> items = data[1];
double totalPrice = data[2];
return Container(
height: 300,
child: Column(
children: [
Expanded(
child: ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
Product product =
Product.fromJson(items[index]['product']);
int quantity = items[index]['quantity'];
return ListTile(
leading: CachedNetworkImage(
imageUrl: product.imageUrl,
width: 50,
height: 50,
fit: BoxFit.cover,
errorWidget: (context, url, error) =>
Icon(Icons.error),
),
title: Text(product.name),
subtitle: Text('¥${product.price} x $quantity'),
);
},
),
),
SizedBox(height: 16),
Text(
'总价: ¥${totalPrice.toStringAsFixed(2)}',
style: TextStyle(fontSize: 18),
),
SizedBox(height: 16),
ElevatedButton(
onPressed: () {
// TODO: 跳转到结算页面
},
child: Text('结算'),
),
],
),
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
},
);
},
);
},
child: ElevatedButton(
onPressed: () async {
String url =
'http://book.musecloud.tech/addcart?productId=${product.id}&quantity=$quantity';
Response response = await _dio.get(url);
if (response.data == 'success') {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('添加到购物车成功'),
duration: Duration(seconds: 2),
),
);
} else {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('添加到购物车失败,请稍后重试'),
duration: Duration(seconds: 2),
),
);
}
},
child: Text('添加到购物车'),
),
),
最后是对应的 model 和 api_service 代码,其中 getShoppingCart 方法返回的数据结构是一个 List,包含购物车所有商品信息、每个商品的信息和总价格:
class Product {
int id;
String name;
String imageUrl;
double price;
String description;
String brand;
Product({
required this.id,
required this.name,
required this.imageUrl,
required this.price,
required this.description,
required this.brand,
});
factory Product.fromJson(Map<String, dynamic> json) {
return Product(
id: json['id'],
name: json['name'],
imageUrl: json['imageUrl'],
price: json['price'].toDouble(),
description: json['description'],
brand: json['brand'],
);
}
}
class ApiService {
static final String baseUrl = "http://book.musecloud.tech";
static Dio _dio = Dio();
// 获取产品列表
static Future<List<Product>> getProductList({
required int page,
required int limit,
}) async {
try {
Response response = await _dio.get(
'$baseUrl/getproductlist',
queryParameters: {
'page': page,
'limit': limit,
'category': '',
'keyword': '',
'minprice': '',
'maxprice': '',
'origin': '',
'brand': '',
'supplier': '',
'isActive': '',
'isDeleted': '',
},
);
List<dynamic> jsonData = jsonDecode(response.data);
List<Product> products =
jsonData.map((json) => Product.fromJson(json)).toList();
return products;
} catch (e) {
throw e;
}
}
// 获取产品详情
static Future<Product> getProductDetail(int id) async {
try {
Response response = await _dio.get('$baseUrl/getproductdetail?id=$id');
dynamic jsonData = jsonDecode(response.data);
Product product = Product.fromJson(jsonData);
return product;
} catch (e) {
throw e;
}
}
// 获取购物车信息
static Future<List<dynamic>> getShoppingCart() async {
try {
Response response = await _dio.get('$baseUrl/getshoppingcart');
dynamic jsonData = jsonDecode(response.data);
return jsonData;
} catch (e) {
throw e;
}
}
}
原文地址: https://www.cveoy.top/t/topic/oiev 著作权归作者所有。请勿转载和采集!