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

为Flutter GridView实现双击、长按、拖放手势功能需求

实现带手势交互的GridView

以下是完整实现代码,包含双击切换颜色、长按选色、拖拽传色三个需求功能:

import 'package:flutter/material.dart';

void main() => runApp(const MaterialApp(home: GridViewGestureDemo()));

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

  @override
  State<GridViewGestureDemo> createState() => _GridViewGestureDemoState();
}

class _GridViewGestureDemoState extends State<GridViewGestureDemo> {
  // 维护所有格子的颜色状态
  final List<Color> _gridColors = [
    Colors.red,
    Colors.yellow,
    Colors.green,
    Colors.black,
  ];
  // 定义颜色循环切换的固定序列
  final List<Color> _colorCycle = [Colors.red, Colors.yellow, Colors.green, Colors.black];
  Color? _draggedColor;

  // 双击切换颜色逻辑:找到当前颜色在序列中的位置,切换到下一个
  void _toggleColor(int index) {
    setState(() {
      final currentIndex = _colorCycle.indexOf(_gridColors[index]);
      _gridColors[index] = _colorCycle[(currentIndex + 1) % _colorCycle.length];
    });
  }

  // 长按弹出颜色选择弹窗
  Future<void> _showColorPicker(int index) async {
    final selectedColor = await showDialog<Color>(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('选择颜色'),
        content: Wrap(
          spacing: 10,
          children: _colorCycle.map((color) {
            return GestureDetector(
              onTap: () => Navigator.pop(context, color),
              child: Container(
                width: 50,
                height: 50,
                color: color,
                decoration: BoxDecoration(
                  border: color == _gridColors[index] ? Border.all(color: Colors.blue, width: 3) : null,
                ),
              ),
            );
          }).toList(),
        ),
      ),
    );
    if (selectedColor != null) {
      setState(() {
        _gridColors[index] = selectedColor;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('GridView 手势交互'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(10),
        child: GridView.builder(
          gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 2,
            mainAxisSpacing: 10,
            crossAxisSpacing: 10,
          ),
          itemCount: _gridColors.length,
          itemBuilder: (context, index) {
            return DragTarget<Color>(
              onAccept: (color) {
                setState(() {
                  _gridColors[index] = color;
                });
              },
              builder: (context, candidateData, rejectedData) {
                return Draggable<Color>(
                  data: _gridColors[index],
                  feedback: Container(
                    width: 100,
                    height: 100,
                    color: _gridColors[index].withOpacity(0.7),
                  ),
                  childWhenDragging: Container(
                    color: Colors.grey[300],
                  ),
                  child: GestureDetector(
                    onDoubleTap: () => _toggleColor(index),
                    onLongPress: () => _showColorPicker(index),
                    child: AnimatedContainer(
                      duration: const Duration(milliseconds: 300),
                      color: _gridColors[index],
                    ),
                  ),
                );
              },
            );
          },
        ),
      ),
    );
  }
}

功能实现细节

1. 双击切换颜色

  • 预先定义_colorCycle序列,固定切换顺序为红→黄→绿→黑循环
  • 给格子绑定onDoubleTap事件,触发_toggleColor方法计算下一个颜色
  • 使用AnimatedContainer实现颜色切换的平滑过渡动画,优化交互体验

2. 长按弹出颜色选择弹窗

  • 绑定onLongPress事件触发弹窗,弹窗内展示所有可选颜色块
  • 当前格子的颜色会显示蓝色边框,作为选中状态提示
  • 选中颜色后关闭弹窗,通过setState更新对应格子的颜色

3. 拖放传色

  • 每个格子同时作为Draggable(拖拽源)和DragTarget(接收目标)
  • 拖拽时传递当前格子的颜色数据,原格子显示灰色占位,拖拽反馈层为半透明颜色块
  • 目标格子接收到颜色后,直接覆盖自身颜色并更新状态

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 18:50:26