Flutter中GridView内IgnorePointer不生效 点击事件仍传递到上层组件
问题原因
Flutter点击事件分为命中测试和事件分发两个核心阶段,当前现象的根本原因是IgnorePointer的特性不匹配需求:
IgnorePointer在命中测试阶段会直接返回false,仅拦截自身和子组件的事件响应,不会阻止上层父组件被命中。- 点击蓝色
_c区域时,IgnorePointer拦截了内部所有Listener的命中,因此不会打印内部的0、1、2、3!日志,但点击区域依然落在GridView外层的Listener范围内,外层Listener会被加入命中列表,事件分发阶段就触发了hello日志打印。
解决方法
有两种成熟方案可以实现完全拦截区域内所有事件、不触发上层回调的需求:
方案1:使用AbsorbPointer替换IgnorePointer(更推荐)
AbsorbPointer的特性是命中测试阶段返回true,会完全吸收区域内的所有点击事件,既不会让子组件响应事件,也不会将事件透传给上层组件,修改_c方法代码即可:
// 蓝色组件,完全拦截所有点击事件 Widget _c() { var l = Listener( // behavior: HitTestBehavior.deferToChild, onPointerDown: (event) => print(0), child: Listener( onPointerDown: (event) => print(1), child: Listener( onPointerDown: (event) => print(2), child: Container( color: Colors.blue, height: 300, width: 300, ), ), ), ); // 将IgnorePointer替换为AbsorbPointer,放在最外层即可完全拦截所有事件 return AbsorbPointer( child: Listener(child: l, onPointerDown: (event) => print("3!")), ); }
方案2:配合stopPropagation手动拦截事件
如果需要保留IgnorePointer的使用,可以在其外层新增一个Listener,主动停止事件冒泡:
Widget _c() { var l = Listener( // behavior: HitTestBehavior.deferToChild, onPointerDown: (event) => print(0), child: Listener( onPointerDown: (event) => print(1), child: Listener( onPointerDown: (event) => print(2), child: Container( color: Colors.blue, height: 300, width: 300, ), ), ), ); var i = IgnorePointer( child: l, ); // 外层新增Listener,命中后直接停止事件冒泡 return Listener( behavior: HitTestBehavior.opaque, onPointerDown: (event) => event.stopPropagation(), child: i, ); }
两种方案修改后,点击蓝色区域不会触发任何日志打印,完全符合预期。
内容的提问来源于stack exchange,提问作者Travis Lee
相关产品推荐
相关产品推荐

