You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter-Dart电商App如何实现带数量选择的动态加购按钮

Flutter 动态「加入购物车」按钮实现方案

实现这个交互不需要复杂的自定义动画,用Flutter自带的隐式动画组件就能快速搞定,核心是通过状态量控制两种UI形态的切换,搭配过渡动画实现要求的淡入效果。

核心实现逻辑

  • 用整型变量记录当前商品在购物车中的数量,初始值为0,对应展示初始「加入购物车」按钮
  • 当数量大于0时,自动切换为数量选择控件,支持加减操作调整数量
  • 用AnimatedSwitcher组件包裹两个切换态的UI,自动处理组件切换时的淡入淡出、轻微缩放过渡,当数量减到0时,初始按钮会自动以淡入效果展示
  • 两个切换态的组件必须设置不同的Key,否则动画组件无法识别UI变化,不会触发过渡效果

可直接复用的核心代码

import 'package:flutter/material.dart';

class DynamicAddCartBtn extends StatefulWidget {
  const DynamicAddCartBtn({super.key, required this.goodsId});
  final String goodsId;

  @override
  State<DynamicAddCartBtn> createState() => _DynamicAddCartBtnState();
}

class _DynamicAddCartBtnState extends State<DynamicAddCartBtn> {
  int cartCount = 0;
  // 统一控制动画过渡时长
  final Duration animDuration = const Duration(milliseconds: 300);

  // 数量变更逻辑,可在这里同步全局购物车数据
  void _changeCount(bool isAdd) {
    setState(() {
      if (isAdd) {
        cartCount++;
      } else {
        cartCount = cartCount > 0 ? cartCount - 1 : 0;
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedSwitcher(
      duration: animDuration,
      // 配置淡入+轻微缩放的过渡效果,避免切换生硬
      transitionBuilder: (child, animation) {
        return FadeTransition(
          opacity: animation,
          child: ScaleTransition(
            scale: Tween(begin: 0.9, end: 1.0).animate(animation),
            child: child,
          ),
        );
      },
      child: cartCount == 0 
        ? _buildInitBtn()
        : _buildCountSelector(),
    );
  }

  // 初始状态的加入购物车按钮
  Widget _buildInitBtn() {
    return ElevatedButton(
      key: const ValueKey('initAddCartBtn'),
      style: ElevatedButton.styleFrom(
        backgroundColor: Colors.red,
        foregroundColor: Colors.white,
        shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
        minimumSize: const Size(100, 36),
      ),
      onPressed: () => _changeCount(true),
      child: const Text('加入购物车'),
    );
  }

  // 数量选择控件
  Widget _buildCountSelector() {
    return Container(
      key: const ValueKey('cartCountSelector'),
      height: 36,
      decoration: BoxDecoration(
        border: Border.all(color: Colors.grey.shade300),
        borderRadius: BorderRadius.circular(20),
      ),
      child: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          IconButton(
            onPressed: () => _changeCount(false),
            iconSize: 18,
            padding: EdgeInsets.zero,
            constraints: const BoxConstraints(minWidth: 36, minHeight: 36),
            icon: const Icon(Icons.remove),
          ),
          SizedBox(
            width: 30,
            child: Text(
              '$cartCount',
              textAlign: TextAlign.center,
              style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
            ),
          ),
          IconButton(
            onPressed: () => _changeCount(true),
            iconSize: 18,
            padding: EdgeInsets.zero,
            constraints: const BoxConstraints(minWidth: 36, minHeight: 36),
            icon: const Icon(Icons.add),
          ),
        ],
      ),
    );
  }
}

踩坑提示:两个切换态组件必须设置不同的ValueKey,否则AnimatedSwitcher会判定组件类型未发生变化,不会触发过渡动画。如果需要对接全局购物车状态,只需要把本地cartCount替换为全局状态中对应商品的数量,在加减方法里调用全局状态的更新方法即可,组件会自动响应状态变化切换UI。

效果示例1

参考效果图1

效果示例2

参考效果图2

内容的提问来源于stack exchange,提问作者Dazzy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 09:24:23