大家好,我是 17,今天的每日 widget 继续交互 widget 的话题,为大家介绍 IgnorePointer 与 AbsorbPointer。
IgnorePointer 与 AbsorbPointer 都可以让 child 无法响应点击事件。IgnorePointer 与 AbsorbPointer 可以和 Listener 配合使用,先了解下 Listener ,再看本篇会非常轻松。
源码分析
IgnorePointer 的 hitTest
@override bool hitTest(BoxHitTestResult result, {required Offset position}) { return !ignoring && super.hitTest(result, position: position); } 复制代码
当 ignoring 为 true, hitTest 返回 false,child 不能响应 pointer 事件。child 不响应事件的原因是 child 没机会把自身加到事件列表。如果 IgnorePointer 是 parent 的唯一 child,parent 不响应事件,原因是对于 parent 来说 child hitTest 失败。 如果 IgnorePointer 的 parent 有多个 child,会继续判断前一个 child,只要有一个 child hitTest 成功,停止判断,可以响应事件。
当 ignoring 为 false,可以认为 IgnorePointer 不起任何作用。
parent 的 behavior == HitTestBehavior.opaque 或 behavior == HitTestBehavior.translucent,就算是 ignoring 为 true,也可以响应 pointer 事件。
AbsorbPointer hitTest
@override bool hitTest(BoxHitTestResult result, {required Offset position}) { return absorbing ? size.contains(position) : super.hitTest(result, position: position); } 复制代码
absorbing 为 true,在 size 范围内点击返回 true, 父级可以响应点击事件,因为对于父级来说, child hitTest 成功。child 不能响应 pointer 事件,因为 child 没机会把自身加到事件列表。
absorbing 为 false,可以认为 AbsorbPointer 不起任何作用。
IgnorePointer 应用场景
源码分析中已经分析了 IgnorePointer 的作用,那么应用场景也就可以想见了。
不响应 pointer 事件
Listener( onPointerDown: (event) { print('parent down'); }, child: IgnorePointer( ignoring: true, child: ElevatedButton( child: Text('IAM17'), onPressed: () { print('child down'); }, )), ) 复制代码
无论是 Listener 还是 ElevatedButton 都不会响应事件。
让前面的兄弟可以有机会进行 hitTest(穿透)
如图,蓝色的 box 完全覆盖在绿色 box 之上,默认情况下,绿色的 box 完全没有机会响应 pointer 事件。但是如果把蓝色的 box ignore 掉,绿色的 box 就可以响应 pointer 事件了。
Stack( children: [ Positioned( left: 0, top: 0, child: Listener( onPointerDown: (event) => print('green click'), child: Container( width: 100, height: 100, color: Colors.green, )), ), Positioned( left: 0, top: 0, child: IgnorePointer( child: Listener( onPointerDown: (event) => print('blue click'), child: Container( width: 150, height: 150, color: Color.fromRGBO(0, 0, 255, .3), )))) ], ) 复制代码
原理在 listener 一文中已经说过了。多 child 的时候,会从后向前判断,后面的 child 测试通过,就不会再判断前面的 chid。加上 IgnorePointer 导致测试不通过,所以就会判断前面的 child 了。
AbsorbPointer 应用场景
不响应 pointer 事件
Listener( onPointerDown: (event) { print('parent down'); }, child: AbsorbPointer( child: ElevatedButton( child: Text('IAM17'), onPressed: () { print('child down'); }, )), ) 复制代码
同样的例子,但换成 AbsorbPointer,ElevatedButton 不响应事件,Listener 可以响应事件。