Flutter GestureDetector无法获取点击事件的问题
Aug 7, 2020 — Flutter
在有TextField的表单界面中,点击空白部分隐藏键盘是基本功能。但是如果GestureDetector直接包裹着TextField是无法响应onTap事件的,比如下面这种情况:
/// 1GestureDetector( onTap: () => FocusManager.instance.primaryFocus?.unfocus(), child: TextField(), )即便再给TextField套一层Container,也是没有响应:
/// 2GestureDetector( onTap: () => FocusManager.instance.primaryFocus?.unfocus(), child: Container( height: 300, color: Colors.grey[200], child: TextField(), ), ),再或者嵌套一个Column:
/// 3GestureDetector( onTap: () => FocusManager.instance.primaryFocus?.unfocus(), child: Column( children: [ TextField(), Spacer(), ], ), )- 方案一
在
Column套一层Container,而且必须设置颜色才会生效。
Container( color: Colors.red,// 必须设置颜色 child: Column( children: [ TextField(), Spacer(), ], ), ),- 方案二
使用
ListView包含TextField
ListView( children: [ TextField(), ], ),这个问题有人在 flutter issues提过:GestureDetector onTap doesn’t work with Column widget (opens in a new window),相关问题和解答可以看看。
下面来聊聊具体的东西。
GestureDetector有个behavior字段,这是个枚举类型:
/// How to behave during hit tests.enum HitTestBehavior { /// Targets that defer to their children receive events within their bounds /// only if one of their children is hit by the hit test. deferToChild,
/// Opaque targets can be hit by hit tests, causing them to both receive /// events within their bounds and prevent targets visually behind them from /// also receiving events. opaque,
/// Translucent targets both receive events within their bounds and permit /// targets visually behind them to also receive events. translucent,}这三种点击事件的作用就是:
- deferToChild:child处理事件,默认
- opaque:自己处理事件
- translucent:自己和child都可以接收事件
Container有个隐藏彩蛋,即当给Container设置color的时候,点击有响应。而color为空,则点击无响应。具体原因查看: Flutter : 关于 HitTestBehavior (opens in a new window)。
基于上面两个前提条件,我们可以得出以下情况:
// 不响应onTapGestureDetector( behavior: HitTestBehavior.deferToChild, // 1 onTap: () => print('hit'), child: Container( height: 300, //color: Colors.red, // 2 ),)// 响应onTapGestureDetector( behavior: HitTestBehavior.opaque, // 1 onTap: () => print('hit'), child: Container( height: 300, //color: Colors.red, // 2 ),)// 响应onTapGestureDetector( behavior: HitTestBehavior.deferToChild, // 1 onTap: () => print('hit'), child: Container( height: 300, color: Colors.red, // 2 ),)