我正在开发一个应用程序,我在 map 上显示标记,如下所示:
它的工作方式是标记在“ map ”小部件上呈现为 Stack
.我的问题是,目前,标记“吸收”了用于控制下方 map 的手势(如果手势在标记上开始)。
因此,我想知道,有没有办法在堆栈中的两个小部件之间传递所有手势事件?理想情况下,标记将忽略(并通过)除 onTap
之外的所有事件。 (因为我仍然希望能够点击标记)。
这是我的特定树:
干杯!
最佳答案
当(视觉上)位于同一堆栈中另一个小部件顶部的小部件被命中时,堆栈将停止任何进一步的 HitTest 。因此,在您的情况下,包含 GoogleMap
的堆栈的第二个子项必须让widget报告没有命中,所以栈会给GoogleMap
有机会对指针事件使用react。 IgnorePointer
可以做到这一点,但是该小部件也不会对其子项进行 HitTest ,因此其子手势检测器永远不会涉及任何手势。在简单的情况下,可以通过交换 IgnorePointer
的顺序来解决这个问题。和 GestureDetector
同时设置后者的 behavior
属性(property)到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
)可以对它的父级采取行动,就好像它永远不会被命中一样,同时仍然对其子级进行 HitTest 。这里我复制了 IgnorePointer
并以这种方式改变了行为(关于 RenderIgnorePointer
的唯一变化是在 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
关于flutter - 在 Stack 中的两个小部件之间传递所有手势,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65269190/