当(视觉上)位于同一堆栈中另一个小部件顶部的小部件被命中时,堆栈将停止任何进一步的命中测试。因此,在您的情况下,包含堆栈的第二个子级GoogleMap
必须使小部件报告它没有被命中,因此堆栈将给出GoogleMap
对指针事件做出反应的机会。IgnorePointer
可以做到这一点,但是该小部件也不会对其子级进行命中测试,因此其子级手势检测器将永远不会参与任何手势。在简单的情况下,可以通过交换顺序来解决IgnorePointer
and GestureDetector
同时设置后者的behavior
财产给HitTestBehaviour.translucent
。例如:
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) => MaterialApp(
home: Stack(
fit: StackFit.expand,
children: [
GestureDetector(
onDoubleTap: () => print("double red"),
child: Container(color: Colors.red),
),
Positioned(
top: 100,
left: 100,
right: 100,
bottom: 100,
child: GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () => print("green"),
child: IgnorePointer(
child: Container(color: Colors.green),
),
),
),
],
),
);
}
不过你的情况比较复杂。更通用的方法是创建一个新的小部件,例如IgnorePointer
(我们称之为TransparentPointer
)可以对其父级采取行动,就好像它从未被击中一样,同时仍然对其子级进行命中测试。这里我复制了IgnorePointer
并以这种方式改变了行为(唯一的改变是RenderIgnorePointer
is in RenderTransparentPointer.hitTest
):
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) => MaterialApp(
home: Stack(
fit: StackFit.expand,
children: [
GestureDetector(
onDoubleTap: () => print("double red"),
child: Container(color: Colors.red),
),
TransparentPointer(
transparent: true,
child: Stack(
children: [
Positioned(
top: 100,
left: 100,
right: 100,
bottom: 100,
child: GestureDetector(
onTap: () => print("green"),
child: Container(color: Colors.green),
),
)
],
),
),
],
),
);
}
class TransparentPointer extends SingleChildRenderObjectWidget {
const TransparentPointer({
Key key,
this.transparent = true,
Widget child,
}) : assert(transparent != null),
super(key: key, child: child);
final bool transparent;
@override
RenderTransparentPointer createRenderObject(BuildContext context) {
return RenderTransparentPointer(
transparent: transparent,
);
}
@override
void updateRenderObject(BuildContext context, RenderTransparentPointer renderObject) {
renderObject
..transparent = transparent;
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(DiagnosticsProperty<bool>('transparent', transparent));
}
}
class RenderTransparentPointer extends RenderProxyBox {
RenderTransparentPointer({
RenderBox child,
bool transparent = true,
}) : _transparent = transparent,
super(child) {
assert(_transparent != null);
}
bool get transparent => _transparent;
bool _transparent;
set transparent(bool value) {
assert(value != null);
if (value == _transparent) return;
_transparent = value;
}
@override
bool hitTest(BoxHitTestResult result, {@required Offset position}) {
// forward hits to our child:
final hit = super.hitTest(result, position: position);
// but report to our parent that we are not hit when `transparent` is true:
return !transparent && hit;
}
@override
void debugFillProperties(DiagnosticPropertiesBuilder properties) {
super.debugFillProperties(properties);
properties.add(DiagnosticsProperty<bool>('transparent', transparent));
}
}
我已将这段代码作为一个小包发布:https://pub.dev/packages/transparent_pointer https://pub.dev/packages/transparent_pointer