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

如何实现Flutter GridView点击时单个容器独立变色显示勾选标记

问题原因

你当前所有网格容器共用同一个_ContainerColor状态变量,点击任意容器触发setState时,所有容器都会读取同一个颜色变量重新渲染,因此会出现联动变色的问题。

实现步骤
  • 第一步:封装单条网格项的数据模型,将每个选项的文本、图标、选中状态独立存储,不再用全局单一变量控制所有项的样式
  • 第二步:初始化所有选项的列表,每个选项的选中状态独立维护
  • 第三步:遍历选项列表生成网格组件,点击时仅修改当前点击项的选中状态,根据单条项的选中状态独立控制容器背景色、右上角勾选标记的显示
核心代码实现

首先在页面State类外定义数据模型:

class FocusOption {
  final String title;
  final IconData icon;
  bool isSelected;

  FocusOption({
    required this.title,
    required this.icon,
    this.isSelected = false,
  });
}

然后在对应页面的State类中,替换原有硬编码的GridView逻辑:

// State类内定义选项列表,把你所有的网格选项都在这里初始化
final List<FocusOption> _focusOptions = [
  FocusOption(
    title: 'Maintaining healthy relationships',
    icon: MyFlutterApp.relationships,
  ),
  // 其余选项按相同格式追加即可
];

@override
Widget build(BuildContext context) {
  double _height = MediaQuery.of(context).size.height;
  final data = ModalRoute.of(context)!.settings;
  String retrieveString = data.arguments == null ? "empty" : data.arguments as String;

  return Scaffold(
    resizeToAvoidBottomInset: false,
    backgroundColor: const Color(0xff31708c),
    body: Padding(
      padding: EdgeInsets.only(left: 30, right: 30, top: _height * 0.2),
      child: Column(
        children: <Widget>[
          Text(
            'Hi $retrieveString! What all would you like to focus on?',
            style: GoogleFonts.montserrat(
                color: Colors.white70,
                fontSize: 19,
                fontWeight: FontWeight.w600
            ),
            textAlign: TextAlign.center,
          ),
          const SizedBox(height: 9),
          Text(
            "You can pick all that apply:",
            style: GoogleFonts.montserrat(
                color: Colors.white70,
                fontSize: 14.5,
                fontWeight: FontWeight.w600
            ),
          ),
          const SizedBox(height: 9),
          Expanded(
            child: GridView.count(
              primary: true,
              shrinkWrap: true,
              padding: const EdgeInsets.all(10),
              childAspectRatio: 1.15,
              crossAxisCount: 2,
              crossAxisSpacing: 25,
              mainAxisSpacing: 25,
              // 遍历选项列表生成网格项
              children: List.generate(_focusOptions.length, (index) {
                final currentItem = _focusOptions[index];
                return GestureDetector(
                  onTap: () {
                    setState(() {
                      // 仅修改当前点击项的选中状态
                      currentItem.isSelected = !currentItem.isSelected;
                    });
                  },
                  child: Stack(
                    children: [
                      Container(
                        padding: const EdgeInsets.all(8),
                        decoration: BoxDecoration(
                            borderRadius: BorderRadius.circular(15),
                            border: Border.all(
                              color: const Color.fromARGB(255, 20, 83, 106),
                              width: 2.5,
                            ),
                            // 单选项独立控制颜色
                            color: currentItem.isSelected ? const Color(0xffa1d0e6) : Colors.white
                        ),
                        child: Column(
                          children: [
                            Align(
                              alignment: Alignment.topCenter,
                              child: Icon(
                                currentItem.icon,
                                color: const Color(0xff31708c),
                                size: 45,
                              ),
                            ),
                            const SizedBox(height: 4),
                            Text(
                              currentItem.title,
                              style: GoogleFonts.montserrat(
                                  fontSize: 14,
                                  fontWeight: FontWeight.w500,
                                  color: const Color(0xff31708c)
                              ),
                              textAlign: TextAlign.center,
                            )
                          ],
                        ),
                      ),
                      // 选中时显示右上角勾选标记
                      if(currentItem.isSelected)
                        const Positioned(
                          top: 8,
                          right: 8,
                          child: Icon(
                            Icons.check_circle,
                            color: Color(0xff31708c),
                            size: 20,
                          ),
                        )
                    ],
                  ),
                );
              }),
            ),
          ),
        ],
      ),
    ),
  );
}
注意事项
  • 后续新增网格选项时,只需要往_focusOptions列表里追加对应的FocusOption实例即可,不需要重复写大量重复的容器代码
  • 如果需要获取所有选中的项,遍历_focusOptions列表筛选isSelected为true的项就能拿到结果

内容的提问来源于stack exchange,提问作者Ta-Ty

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 21:36:25