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

Flutter子组件传值与状态管理:ChipSet单选功能实现问题

解决方案:父子组件回调+统一状态管理

这个问题其实很适合用父组件统一管理状态+子组件回调的模式来解决,咱们一步步改造代码,保证优雅又好用:

1. 改造MyChip:把状态和点击逻辑交给父组件

MyChip只需要负责UI展示,激活状态和点击事件都由父组件控制。我们给它新增一个onTap回调参数,让父组件处理点击后的逻辑:

import 'package:flutter/material.dart';

class MyChip extends StatelessWidget {
  final bool active;
  final Color color;
  final IconData icon;
  final String text;
  final EdgeInsets padding;
  final VoidCallback? onTap; // 新增:父组件传递的点击回调

  const MyChip({
    Key? key,
    required this.color,
    required this.icon,
    required this.text,
    this.active = false,
    this.padding = const EdgeInsets.all(0),
    this.onTap,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: onTap, // 直接触发父组件传过来的回调
      child: Container(
        padding: const EdgeInsets.all(4),
        margin: const EdgeInsets.only(right: 6),
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(12),
          color: active ? color : Colors.white,
        ),
        child: Row(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Icon(icon, size: 15, color: active ? Colors.white : Colors.black),
            Padding(
              padding: padding,
              child: Text(
                text,
                style: TextStyle(
                  fontSize: 12,
                  color: active ? Colors.white : Colors.black, // 激活时文字变白,提升体验
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

2. 改造ChipSet:统一管理激活状态+对外回调

ChipSet作为父组件,需要维护当前选中的Chip索引,同时给每个子Chip设置激活状态和点击回调。另外新增一个对外回调,把选中的Chip数据传递给上层组件:

import 'package:flutter/material.dart';
import 'package:hello_world/widgets/chip.dart';

class ChipSet extends StatefulWidget {
  final List<MyChip> chips;
  final ValueChanged<MyChip>? onChipSelected; // 新增:对外传递选中的Chip

  const ChipSet({
    Key? key,
    required this.chips,
    this.onChipSelected,
  }) : super(key: key);

  @override
  _ChipSetState createState() => _ChipSetState();
}

class _ChipSetState extends State<ChipSet> {
  int? _selectedIndex; // 记录当前选中的Chip索引

  @override
  Widget build(BuildContext context) {
    return Row(
      crossAxisAlignment: CrossAxisAlignment.center,
      children: List.generate(widget.chips.length, (index) {
        final originalChip = widget.chips[index];
        // 复制原Chip的属性,替换激活状态和点击回调
        return MyChip(
          key: originalChip.key,
          color: originalChip.color,
          icon: originalChip.icon,
          text: originalChip.text,
          padding: originalChip.padding,
          active: _selectedIndex == index, // 父组件控制激活状态
          onTap: () {
            setState(() {
              _selectedIndex = index; // 更新选中状态,确保同一时间只有一个激活
            });
            // 触发对外回调,把选中的Chip传递出去
            if (widget.onChipSelected != null) {
              widget.onChipSelected!(originalChip);
            }
          },
        );
      }),
    );
  }
}

3. 使用示例

在你的上层组件中,就可以这样使用ChipSet,并且拿到选中的Chip数据:

ChipSet(
  chips: [
    const MyChip(
      color: Colors.blue,
      icon: Icons.home,
      text: '首页',
      padding: EdgeInsets.only(left: 4),
    ),
    const MyChip(
      color: Colors.green,
      icon: Icons.person,
      text: '我的',
      padding: EdgeInsets.only(left: 4),
    ),
    const MyChip(
      color: Colors.orange,
      icon: Icons.shopping_cart,
      text: '购物车',
      padding: EdgeInsets.only(left: 4),
    ),
  ],
  onChipSelected: (selectedChip) {
    print('选中了Chip:${selectedChip.text}');
    // 这里可以处理选中后的业务逻辑,比如页面跳转、状态更新等
  },
)

为什么这么做?

  • 状态统一:所有Chip的激活状态都由ChipSet管理,避免多个子组件各自维护状态导致的不一致问题。
  • 职责分离:MyChip只负责UI渲染,ChipSet负责状态管理和逻辑处理,符合单一职责原则。
  • 扩展性强:对外回调onChipSelected让上层组件可以灵活处理选中事件,不需要修改ChipSet内部逻辑。

内容的提问来源于stack exchange,提问作者Božidar Vulićević

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:55:39