Flutter 零基础入门(二十五):手势 GestureDetector 与 InkWell
在上一篇中,我们学习了 Flutter 的按钮体系:
- TextButton
- ElevatedButton
- IconButton
按钮解决了**"标准交互"**的问题。
但在真实 App 中,你会发现:
很多地方根本不是按钮,却可以被点击
比如:
- 整个列表项
- 一张图片
- 一个卡片
- 自定义区域
这正是本篇要学习的内容。
一、为什么需要 GestureDetector 和 InkWell?
📌 Flutter 的一个核心设计理念:
任何 Widget 都可以有交互
GestureDetector 和 InkWell 的作用是:
给任意 Widget 添加点击、滑动等手势能力
二、GestureDetector:最基础、最自由
1️⃣ 什么是 GestureDetector?
GestureDetector 是一个 手势监听器,本身不负责 UI。
2️⃣ 最简单用法(点击)
dart
GestureDetector(
onTap: () {
print('被点击了');
},
child: Container(
padding: EdgeInsets.all(16),
color: Colors.blue,
child: Text('点击区域'),
),
)
特点:
- 没有任何视觉反馈
- 只负责"监听"
3️⃣ 常用回调
- onTap(点击)
- onDoubleTap(双击)
- onLongPress(长按)
4️⃣ GestureDetector 的特点总结
✅ 非常灵活
❌ 没有水波纹
❌ 用户感知较弱
三、InkWell:带水波纹的点击(重点)
1️⃣ 什么是 InkWell?
InkWell 是 Material 体系的一部分,特点是:
点击时有水波纹效果
2️⃣ 基本用法
InkWell(
onTap: () {
print('点击了');
},
child: Padding(
padding: EdgeInsets.all(16),
child: Text('点击我'),
),
)
3️⃣ 水波纹的前提条件(重要)
⚠️ InkWell 必须有 Material 祖先
正确写法:
Material(
child: InkWell(
onTap: () {},
child: Container(
padding: EdgeInsets.all(16),
child: Text('点击'),
),
),
)
四、GestureDetector vs InkWell 对比
| 对比项 | GestureDetector | InkWell |
|---|---|---|
| 是否有反馈 | ❌ | ✅ |
| 是否依赖 Material | ❌ | ✅ |
| 灵活度 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
| 常见场景 | 自定义交互 | 列表 / 卡片 |
📌 经验法则:
列表、卡片 → InkWell
高度自定义 → GestureDetector
五、点击整行列表项(经典场景)
InkWell(
onTap: () {},
child: Padding(
padding: EdgeInsets.all(16),
child: Row(
children: [
Icon(Icons.person),
SizedBox(width: 12),
Expanded(child: Text('用户信息')),
Icon(Icons.arrow_forward_ios, size: 16),
],
),
),
)
这是 99% App 列表项的点击方式。
六、设置水波纹形状(圆角)
InkWell(
borderRadius: BorderRadius.circular(12),
onTap: () {},
child: Container(
padding: EdgeInsets.all(16),
child: Text('圆角点击'),
),
)
⚠️ 建议:
borderRadius 与 UI 圆角保持一致
七、点击图片或卡片
InkWell(
onTap: () {},
child: ClipRRect(
borderRadius: BorderRadius.circular(12),
child: Image.asset('assets/images/banner.png'),
),
)
八、一个完整"可点击卡片"示例
Material(
borderRadius: BorderRadius.circular(12),
child: InkWell(
borderRadius: BorderRadius.circular(12),
onTap: () {},
child: Container(
padding: EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'卡片标题',
style: TextStyle(fontWeight: FontWeight.bold),
),
SizedBox(height: 8),
Text('这是卡片内容'),
],
),
),
),
)
这是非常专业的 Flutter 写法。
九、新手常见误区总结
❌ 用 GestureDetector 却想要水波纹
❌ 忘记 Material 导致 InkWell 没效果
❌ 整个页面都包 GestureDetector
❌ borderRadius 不一致导致水波纹溢出
十、这一篇你真正学会了什么?
你已经掌握了:
- 给任意 Widget 添加点击事件
- GestureDetector 与 InkWell 的区别
- 水波纹的正确使用方式
- 实战级点击区域写法
现在你的 App:
不再"点哪哪没反应"了 😄
十一、总结
本篇你学会了:
- Flutter 的手势系统基础
- 常见点击场景实现
- 专业交互写法
🔜 下一篇预告
《Flutter 零基础入门(二十六):StatefulWidget 与状态更新 setState》
下一篇我们将学习:
- 什么是"状态"
- StatelessWidget vs StatefulWidget
- setState 的作用
- 点击后界面如何更新
从下一篇开始:
Flutter 真正的"动态 UI"正式登场 ⚡