为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
相关产品推荐
相关产品推荐

