Flutter商城商品详情页添加购物车按钮和数量选择功能

本文将介绍如何在Flutter商城商品详情页添加购物车按钮和数量选择功能,包括悬浮购物车按钮,长按动画展开购物车商品列表,添加结算按钮,以及网络请求和数据解析。

需求分析

  • 商品详情页缺少一个添加到购物车按钮,而且没有数量选择功能。
  • 购物车按钮想要做成悬浮的,长按可以动画展开显示所有购物车商品,然后添加一个结算按钮,可以直接跳转到结算页面。
  • 所有网络请求都要写在ApiService类中,并且写好对应的modelapi_service

接口说明

  • 添加到购物车接口:http://book.musecloud.tech/addcart?productId=-1896935422&quantity=1,如果添加成功则返回success
  • 购物车接口:http://book.musecloud.tech/getshoppingcart,返回的数据是JSON数组,第一个是购物车所有商品信息,第二个是每个商品的信息,第三个是总价格。

代码实现

1. Model类

import 'dart:convert';

class CartItem {
  final int productId;
  final String productName;
  final double price;
  final int quantity;
  final String imageUrl;

  CartItem({
    required this.productId,
    required this.productName,
    required this.price,
    required this.quantity,
    required this.imageUrl,
  });

  factory CartItem.fromJson(Map<String, dynamic> json) {
    return CartItem(
      productId: json['productId'],
      productName: json['productName'],
      price: json['price'].toDouble(),
      quantity: json['quantity'],
      imageUrl: json['imageUrl'],
    );
  }
}

class CartData {
  final List<CartItem> cartItems;
  final double totalPrice;

  CartData({
    required this.cartItems,
    required this.totalPrice,
  });

  factory CartData.fromJson(List<dynamic> json) {
    return CartData(
      cartItems: List<CartItem>.from(json[1].map((item) => CartItem.fromJson(item))),
      totalPrice: json[2].toDouble(),
    );
  }
}

2. ApiService类

import 'dart:convert';
import 'package:dio/dio.dart';
import '../models/product.dart';
import '../models/cart.dart';

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 productId) async {
    try {
      Response response = await _dio.get('$baseUrl/getproductdetail?id=$productId');
      Map<String, dynamic> jsonData = jsonDecode(response.data);
      return Product.fromJson(jsonData);
    } catch (e) {
      throw e;
    }
  }

  // 添加到购物车
  static Future<String> addToCart(int productId, int quantity) async {
    try {
      Response response = await _dio.get('$baseUrl/addcart', queryParameters: {
        'productId': productId,
        'quantity': quantity,
      });
      return response.data;
    } catch (e) {
      throw e;
    }
  }

  // 获取购物车数据
  static Future<CartData> getShoppingCart() async {
    try {
      Response response = await _dio.get('$baseUrl/getshoppingcart');
      List<dynamic> jsonData = jsonDecode(response.data);
      return CartData.fromJson(jsonData);
    } catch (e) {
      throw e;
    }
  }
}

3. 商品详情页代码

import 'package:cached_network_image/cached_network_image.dart';
import 'package:ecommerce_muse/models/product.dart';
import 'package:ecommerce_muse/services/api_service.dart';
import 'package:flutter/material.dart';

class ProductDetailPage extends StatefulWidget {
  final int productId;

  ProductDetailPage({required this.productId});

  @override
  _ProductDetailPageState createState() =>
      _ProductDetailPageState(productId: productId);
}

class _ProductDetailPageState extends State<ProductDetailPage> {
  final int productId;
  late Future<Product> _productFuture;
  int _quantity = 1;
  bool _showShoppingCart = false;

  _ProductDetailPageState({required this.productId});

  @override
  void initState() {
    super.initState();
    _productFuture = ApiService.getProductDetail(productId);
  }

  void _addToCart() async {
    try {
      String result = await ApiService.addToCart(productId, _quantity);
      if (result == 'success') {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Text('添加到购物车成功'),
            duration: Duration(seconds: 2),
          ),
        );
      } else {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Text('添加到购物车失败,请重试'),
            duration: Duration(seconds: 2),
          ),
        );
      }
    } catch (e) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text('添加到购物车失败,请检查网络连接'),
          duration: Duration(seconds: 2),
        ),
      );
    }
  }

  Widget _buildFloatingCartButton() {
    return FloatingActionButton(
      onPressed: () {
        setState(() {
          _showShoppingCart = !_showShoppingCart;
        });
      },
      child: Stack(
        children: [
          Icon(Icons.shopping_cart),
          Positioned(
            top: 0,
            right: 0,
            child: Container(
              padding: EdgeInsets.all(2),
              decoration: BoxDecoration(
                color: Colors.red,
                borderRadius: BorderRadius.circular(10),
              ),
              child: Text(
                '1', // 替换成购物车中商品数量的变量
                style: TextStyle(
                  color: Colors.white,
                  fontSize: 12,
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildQuantitySelector() {
    return Row(
      children: [
        IconButton(
          onPressed: () {
            setState(() {
              if (_quantity > 1) {
                _quantity--;
              }
            });
          },
          icon: Icon(Icons.remove),
        ),
        Text(
          _quantity.toString(),
          style: TextStyle(fontSize: 18),
        ),
        IconButton(
          onPressed: () {
            setState(() {
              _quantity++;
            });
          },
          icon: Icon(Icons.add),
        ),
      ],
    );
  }

  Widget _buildShoppingCart() {
    return Container(
      padding: EdgeInsets.all(16.0),
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: BorderRadius.circular(8.0),
        boxShadow: [BoxShadow(color: Colors.grey, blurRadius: 4.0)],
      ),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: [
          Text('购物车商品', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
          // 添加购物车商品列表
          // ...
          ElevatedButton(
            onPressed: () {
              // 跳转到结算页面
            },
            child: Text('结算'),
          ),
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('商品详情'),
      ),
      body: Stack(
        children: [
          FutureBuilder<Product>(
            future: _productFuture,
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                return _buildProductDetail(snapshot.data!);
              } else if (snapshot.hasError) {
                return Center(
                  child: Text('加载商品详情失败'),
                );
              }
              return Center(
                child: CircularProgressIndicator(),
              );
            },
          ),
          if (_showShoppingCart) _buildShoppingCart(),
        ],
      ),
      floatingActionButton: _buildFloatingCartButton(),
    );
  }

  Widget _buildProductDetail(Product product) {
    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: 8),
                Text(
                  '数量: ',
                  style: TextStyle(fontSize: 18),
                ),
                _buildQuantitySelector(),
                SizedBox(height: 8),
                ElevatedButton(
                  onPressed: _addToCart,
                  child: Text('添加到购物车'),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

解释说明

  1. CartItem类用于解析每个购物车商品信息,CartData类用于解析整个购物车数据。
  2. ApiService类中添加了addToCartgetShoppingCart方法,分别用于添加商品到购物车和获取购物车数据。
  3. ProductDetailPage类中添加了以下功能:
    • 使用_quantity变量保存商品数量,初始值为1。
    • 使用_showShoppingCart变量控制购物车列表是否显示,初始值为false
    • 使用_buildFloatingCartButton方法创建悬浮的购物车按钮,点击按钮可以控制购物车列表的显示隐藏。
    • 使用_buildQuantitySelector方法创建商品数量选择器。
    • 使用_buildShoppingCart方法创建购物车列表,包括商品列表和结算按钮。
    • _buildProductDetail方法中添加商品数量选择器和添加到购物车按钮。
  4. 购物车按钮添加动画效果,可以参考Flutter官方文档中的动画相关内容。

总结

本文介绍了如何在Flutter商城商品详情页添加购物车按钮和数量选择功能,并提供了相应的代码实现。用户可以根据自己的需求进行调整和完善。

注意:

  • 需要确保已配置好Flutter开发环境,并安装了Dio、cached_network_image等依赖库。
  • 需要修改ApiService类中的baseUrl为实际的API地址。
  • 需要将_buildShoppingCart方法中的// 添加购物车商品列表部分替换成实际的购物车商品列表。
  • 需要将_buildFloatingCartButton方法中的1替换成购物车中商品数量的变量。
  • 需要将_buildShoppingCart方法中的// 跳转到结算页面部分替换成实际的跳转逻辑。

希望本文对大家有所帮助。

Flutter商城商品详情页添加购物车按钮和数量选择功能

原文地址: https://www.cveoy.top/t/topic/oieF 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录