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

Flutter:图片分割为网格并为每个网格按钮绑定不同下拉菜单求助

Flutter 图片网格分割 + 区域按钮与自定义下拉菜单实现

一、9等分网格实现示例

以下是完整的可运行代码,实现图片上层覆盖3x3可点击网格,每个网格点击后弹出独立下拉菜单:

import 'package:flutter/material.dart';

class ImageGridMenu extends StatefulWidget {
  const ImageGridMenu({super.key});

  @override
  State<ImageGridMenu> createState() => _ImageGridMenuState();
}

class _ImageGridMenuState extends State<ImageGridMenu> {
  // 每个网格对应的下拉选项,索引对应网格位置
  final List<List<String>> _gridOptions = List.generate(9, (index) => [
    '选项 ${index+1}-1',
    '选项 ${index+1}-2',
    '选项 ${index+1}-3',
  ]);

  // 存储每个网格的选中值与菜单展开状态
  final List<String?> _selectedOptions = List.filled(9, null);
  final List<bool> _showDropdown = List.filled(9, false);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('图片网格菜单')),
      body: Stack(
        children: [
          // 底层图片,按容器尺寸填充
          Positioned.fill(
            child: Image.network(
              'https://picsum.photos/800/800', // 替换为你的本地/网络图片路径
              fit: BoxFit.cover,
            ),
          ),
          // 上层3x3可点击网格
          GridView.count(
            crossAxisCount: 3,
            physics: const NeverScrollableScrollPhysics(), // 禁用网格滚动,避免冲突
            children: List.generate(9, (index) {
              return GestureDetector(
                onTap: () => setState(() => _showDropdown[index] = !_showDropdown[index]),
                child: Stack(
                  children: [
                    // 透明背景(调试时可改为半透明,方便查看网格边界)
                    Container(color: Colors.black.withOpacity(0.1)),
                    // 下拉菜单,仅在展开状态显示
                    if (_showDropdown[index])
                      Positioned(
                        bottom: 0,
                        left: 0,
                        right: 0,
                        child: Container(
                          color: Colors.white,
                          child: DropdownButtonFormField<String>(
                            value: _selectedOptions[index],
                            items: _gridOptions[index].map((option) => DropdownMenuItem(
                              value: option,
                              child: Text(option),
                            )).toList(),
                            onChanged: (value) {
                              setState(() {
                                _selectedOptions[index] = value;
                                _showDropdown[index] = false; // 选择后收起菜单
                              });
                            },
                            decoration: const InputDecoration(
                              border: OutlineInputBorder(),
                              contentPadding: EdgeInsets.symmetric(horizontal: 8),
                            ),
                          ),
                        ),
                      ),
                    // 当前选中值的提示
                    if (_selectedOptions[index] != null && !_showDropdown[index])
                      Align(
                        alignment: Alignment.center,
                        child: Container(
                          padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
                          color: Colors.white.withOpacity(0.8),
                          child: Text(_selectedOptions[index]!),
                        ),
                      ),
                  ],
                ),
              );
            }),
          ),
        ],
      ),
    );
  }
}

二、门形布局实现示例

如果需要非网格的门形区域划分(顶部长条+左右中部+底部长条),可以用Column+Row组合实现:

import 'package:flutter/material.dart';

class DoorShapeMenu extends StatefulWidget {
  const DoorShapeMenu({super.key});

  @override
  State<DoorShapeMenu> createState() => _DoorShapeMenuState();
}

class _DoorShapeMenuState extends State<DoorShapeMenu> {
  // 门形4个区域的下拉选项
  final List<List<String>> _doorOptions = [
    ['顶部选项1', '顶部选项2'],
    ['左中选项1', '左中选项2', '左中选项3'],
    ['右中选项1', '右中选项2'],
    ['底部选项1', '底部选项2', '底部选项3'],
  ];

  final List<String?> _selectedOptions = List.filled(4, null);
  final List<bool> _showDropdown = List.filled(4, false);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('门形图片菜单')),
      body: Stack(
        children: [
          Positioned.fill(
            child: Image.network(
              'https://picsum.photos/800/1200',
              fit: BoxFit.cover,
            ),
          ),
          // 门形区域划分
          Column(
            children: [
              _buildDoorSection(0, height: 80),
              Expanded(
                child: Row(
                  children: [
                    Expanded(child: _buildDoorSection(1)),
                    Expanded(child: _buildDoorSection(2)),
                  ],
                ),
              ),
              _buildDoorSection(3, height: 80),
            ],
          ),
        ],
      ),
    );
  }

  // 封装区域构建逻辑
  Widget _buildDoorSection(int index, {double? height}) {
    return GestureDetector(
      onTap: () => setState(() => _showDropdown[index] = !_showDropdown[index]),
      child: Container(
        height: height,
        color: Colors.black.withOpacity(0.1),
        child: Stack(
          children: [
            if (_showDropdown[index])
              Positioned(
                bottom: 0,
                left: 0,
                right: 0,
                child: Container(
                  color: Colors.white,
                  child: DropdownButtonFormField<String>(
                    value: _selectedOptions[index],
                    items: _doorOptions[index].map((option) => DropdownMenuItem(
                      value: option,
                      child: Text(option),
                    )).toList(),
                    onChanged: (value) {
                      setState(() {
                        _selectedOptions[index] = value;
                        _showDropdown[index] = false;
                      });
                    },
                  ),
                ),
              ),
            if (_selectedOptions[index] != null && !_showDropdown[index])
              Align(
                alignment: Alignment.center,
                child: Container(
                  padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
                  color: Colors.white.withOpacity(0.8),
                  child: Text(_selectedOptions[index]!),
                ),
              ),
          ],
        ),
      ),
    );
  }
}

关键注意点

  1. 图片替换:将示例中的网络图片替换为本地资源(使用AssetImage)或你的目标图片URL
  2. 样式自定义:可修改DropdownButtonFormField的decoration、dropdownColor等属性匹配UI风格
  3. 交互优化:若需点击空白区域收起所有菜单,可在最外层Stack添加GestureDetector,点击时重置所有_showDropdown为false
  4. 复杂形状:如需非规则门形(弧形、缺口),可使用ClipPath自定义裁剪路径,将按钮区域裁剪为目标形状后添加点击事件

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 15:27:31