Flutter咖啡商城:如何将Toggle Button选中数据传入购物车
解决方案
要把Toggle Button的选中数据传递到购物车页面,核心是让详情页(父组件)获取Toggle组件(子组件)的选中状态,再将这些状态和咖啡商品信息一起加入购物车,最终在购物车页面展示。具体步骤如下:
1. 修改Toggle组件,向外暴露选中状态
让WholeOrGround和OneTimeSubscribe通过回调函数把选中值传递给父组件,而非封闭维护状态:
修改WholeOrGround组件
class WholeOrGround extends StatefulWidget { // 定义回调,传递选中的研磨方式 final ValueChanged<String> onGrindSelected; // 可选:设置默认选中值 final String initialValue; const WholeOrGround({ Key? key, required this.onGrindSelected, this.initialValue = 'Whole Bean', }) : super(key: key); @override State<WholeOrGround> createState() => _WholeOrGround(); } class _WholeOrGround extends State<WholeOrGround> { late List<bool> isSelected; @override void initState() { super.initState(); // 根据初始值初始化选中状态 isSelected = [ widget.initialValue == 'Whole Bean', widget.initialValue == 'Ground' ]; } @override Widget build(BuildContext context) { return ToggleButtons( color: Colors.amber, borderColor: Colors.amber, splashColor: const Color.fromARGB(255, 251, 187, 208), borderWidth: 3, borderRadius: BorderRadius.circular(10), selectedColor: Colors.lightBlue, onPressed: (int newIndex) { setState(() { for (int index = 0; index < isSelected.length; index++) { isSelected[index] = index == newIndex; } }); // 通过回调传递选中值 final selectedGrind = newIndex == 0 ? 'Whole Bean' : 'Ground'; widget.onGrindSelected(selectedGrind); }, isSelected: isSelected, children: const [ Padding( padding: EdgeInsets.all(4), child: Text('Whole Bean', style: TextStyle(fontWeight: FontWeight.bold))), Padding( padding: EdgeInsets.all(4), child: Text('Ground', style: TextStyle(fontWeight: FontWeight.bold)), ) ], ); } }
同理修改OneTimeSubscribe组件
class OneTimeSubscribe extends StatefulWidget { final ValueChanged<String> onPaymentSelected; final String initialValue; const OneTimeSubscribe({ Key? key, required this.onPaymentSelected, this.initialValue = 'one-time payment', }) : super(key: key); @override State<OneTimeSubscribe> createState() => _OneTimeSubscribe(); } class _OneTimeSubscribe extends State<OneTimeSubscribe> { late List<bool> isSelected; @override void initState() { super.initState(); isSelected = [ widget.initialValue == 'one-time payment', widget.initialValue == 'subscription' ]; } @override Widget build(BuildContext context) { return ToggleButtons( // 保留原有样式设置 onPressed: (int newIndex) { setState(() { for (int index = 0; index < isSelected.length; index++) { isSelected[index] = index == newIndex; } }); final selectedPayment = newIndex == 0 ? 'one-time payment' : 'subscription'; widget.onPaymentSelected(selectedPayment); }, isSelected: isSelected, children: const [ Padding( padding: EdgeInsets.all(4), child: Text('One-Time Payment', style: TextStyle(fontWeight: FontWeight.bold))), Padding( padding: EdgeInsets.all(4), child: Text('Subscription', style: TextStyle(fontWeight: FontWeight.bold)), ) ], ); } }
2. 在详情页父组件中接收选中状态
在详情页声明变量存储研磨方式和支付类型,通过回调获取Toggle组件的选中值:
class CoffeeDetailPage extends StatefulWidget { final CoffeeItem coffee; // 当前展示的咖啡商品 const CoffeeDetailPage({Key? key, required this.coffee}) : super(key: key); @override State<CoffeeDetailPage> createState() => _CoffeeDetailPageState(); } class _CoffeeDetailPageState extends State<CoffeeDetailPage> { final _formKey = GlobalKey<FormState>(); String _selectedGrind = 'Whole Bean'; String _selectedPayment = 'one-time payment'; // 添加到购物车的方法 void addToCart() { // 创建包含选中状态的购物车项(需先修改CoffeeItem模型) final cartItem = CoffeeItem( title: widget.coffee.title, productPrice: widget.coffee.productPrice, image: widget.coffee.image, grindSetting: _selectedGrind, paymentType: _selectedPayment, ); // 调用你的购物车添加逻辑(比如Provider、Bloc等状态管理方式) // 示例:Provider.of<CartProvider>(context, listen: false).addItem(cartItem); } @override Widget build(BuildContext context) { return Scaffold( // 其他页面内容... Form( key: _formKey, child: Column( children: [ WholeOrGround( onGrindSelected: (grind) { setState(() { _selectedGrind = grind; }); }, initialValue: _selectedGrind, ), const SizedBox(height: 15), OneTimeSubscribe( onPaymentSelected: (payment) { setState(() { _selectedPayment = payment; }); }, initialValue: _selectedPayment, ), const SizedBox(height: 15), ElevatedButton( onPressed: addToCart, child: const Text('Add to Cart'), ) ], ), ), ); } }
3. 修改CoffeeItem模型,新增字段存储选中状态
确保模型包含研磨方式和支付类型字段:
class CoffeeItem { final String title; final String productPrice; final String image; final String grindSetting; // 新增字段 final String paymentType; // 新增字段 CoffeeItem({ required this.title, required this.productPrice, required this.image, required this.grindSetting, required this.paymentType, }); }
4. 在购物车页面展示选中的数据
修改购物车列表项,展示研磨方式和支付类型:
Expanded( child: ListView.builder( itemCount: value.cart.length, itemBuilder: (context, index) { final CoffeeItem coffeeItem = value.cart[index]; final String coffeeTitle = coffeeItem.title; final String coffeePrice = coffeeItem.productPrice; final String coffeeImage = coffeeItem.image; // 直接从购物车项中获取选中的数据 final String grindSetting = coffeeItem.grindSetting; final String paymentType = coffeeItem.paymentType; return Container( decoration: BoxDecoration( borderRadius: BorderRadius.circular(15), color: const Color.fromARGB(255, 219, 176, 243)), margin: const EdgeInsets.only(left: 20, top: 20, right: 20), child: ListTile( leading: Image.asset(coffeeImage), title: Text(coffeeTitle), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('\$$coffeePrice'), Text('研磨方式: $grindSetting'), Text('支付类型: $paymentType'), ], ), trailing: IconButton( onPressed: () => removeFromCart(coffeeItem, context), icon: const Icon(Icons.delete)), ), ); }, ), )
内容的提问来源于stack exchange,提问作者KRAP
相关产品推荐
相关产品推荐

