我正在尝试使 GestureDetector 在堆栈中工作,堆栈顶部有一个容器,但从未调用 onTap 回调。
如您所见,即使使用它也不起作用 HitTestBehavior.translucent
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Stack(
children: <Widget>[
GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
print('tap');
},
child: Container(color: Colors.blue),
),
Container(color: Colors.white),
],
),
),
);
}
Run Code Online (Sandbox Code Playgroud)
我知道我想在另一个小部件下方捕获点击事件可能很奇怪,但在我的真实情况下,顶部的小部件是透明的,有时具有渐变。
Var*_*iak 19
好的,我想我自己找到了解决方案。我希望有一个更简单的解决方案,但它对我有用。我遇到的问题是 Stack 小部件不会将命中测试传递给所有孩子,而只会将命中测试传递给第一个被命中的孩子。我所做的是重写了 Stack 的 RenderBox 使用的命中检测算法。我真的不打算走这么远,我仍在等待更好的答案。这是我的代码,使用风险自负:
class CustomStack extends Stack {
CustomStack({children}) : super(children: children);
@override
CustomRenderStack createRenderObject(BuildContext context) {
return CustomRenderStack(
alignment: alignment,
textDirection: textDirection ?? Directionality.of(context),
fit: fit,
overflow: overflow,
);
}
}
class CustomRenderStack extends RenderStack {
CustomRenderStack({alignment, textDirection, fit, overflow})
: super(
alignment: alignment,
textDirection: textDirection,
fit: fit,
overflow: overflow);
@override
bool hitTestChildren(BoxHitTestResult result, {Offset position}) {
var stackHit = false;
final children = getChildrenAsList();
for (var child in children) {
final StackParentData childParentData = child.parentData;
final childHit = result.addWithPaintOffset(
offset: childParentData.offset,
position: position,
hitTest: (BoxHitTestResult result, Offset transformed) {
assert(transformed == position - childParentData.offset);
return child.hitTest(result, position: transformed);
},
);
if (childHit) stackHit = true;
}
return stackHit;
}
}
Run Code Online (Sandbox Code Playgroud)
Hos*_*adi 14
这可以通过IgnorePointer.
您可以Container用IgnorePointer.
Stack(
children:[
(...your down widget which should handle the tap...)
IgnorePointer(
child: (... your top widget which must be transparent to any tap ...)
)
]
)
Run Code Online (Sandbox Code Playgroud)
然后您的顶部小部件对手势事件变得透明。事件将由 上最顶层的检测器捕获(Stack如果有)。
例如,您可以对代码进行少量更改以达到所需的结果,如下所示:
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Stack(
children: <Widget>[
GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: () {
print('tap');
},
child: Container(color: Colors.blue),
),
IgnorePointer(ignoring:true,child:Container(color: Colors.white)),
],
),
),
);
}
Run Code Online (Sandbox Code Playgroud)
2021 年 10 月更新flutter > 2.5
Stack用这个小部件替换你的CustomStack:
class CustomStack extends Stack {
CustomStack({children}) : super(children: children);
@override
CustomRenderStack createRenderObject(BuildContext context) {
return CustomRenderStack(
alignment: alignment,
textDirection: textDirection ?? Directionality.of(context),
fit: fit,
);
}
}
class CustomRenderStack extends RenderStack {
CustomRenderStack({alignment, textDirection, fit, overflow})
: super(alignment: alignment, textDirection: textDirection, fit: fit);
@override
bool hitTestChildren(BoxHitTestResult result, {required Offset position}) {
var stackHit = false;
final children = getChildrenAsList();
for (var child in children) {
final StackParentData childParentData =
child.parentData as StackParentData;
final childHit = result.addWithPaintOffset(
offset: childParentData.offset,
position: position,
hitTest: (BoxHitTestResult result, Offset transformed) {
assert(transformed == position - childParentData.offset);
return child.hitTest(result, position: transformed);
},
);
if (childHit) stackHit = true;
}
return stackHit;
}
}
Run Code Online (Sandbox Code Playgroud)
受到 @Vardiak 和 @HugoH 的启发,修复了错误(即updateRenderObject添加 - 否则代码有错误)
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
class MultiHitStack extends Stack {
MultiHitStack({
super.key,
super.alignment = AlignmentDirectional.topStart,
super.textDirection,
super.fit = StackFit.loose,
super.clipBehavior = Clip.hardEdge,
super.children = const <Widget>[],
});
@override
RenderMultiHitStack createRenderObject(BuildContext context) {
return RenderMultiHitStack(
alignment: alignment,
textDirection: textDirection ?? Directionality.maybeOf(context),
fit: fit,
clipBehavior: clipBehavior,
);
}
@override
void updateRenderObject(BuildContext context, RenderMultiHitStack renderObject) {
renderObject
..alignment = alignment
..textDirection = textDirection ?? Directionality.maybeOf(context)
..fit = fit
..clipBehavior = clipBehavior;
}
}
class RenderMultiHitStack extends RenderStack {
RenderMultiHitStack({
super.children,
super.alignment = AlignmentDirectional.topStart,
super.textDirection,
super.fit = StackFit.loose,
super.clipBehavior = Clip.hardEdge,
});
// NOTE MODIFIED FROM [RenderStack.hitTestChildren], i.e. [defaultHitTestChildren]
@override
bool hitTestChildren(BoxHitTestResult result, {required Offset position}) {
// NOTE MODIFIED
var childHit = false;
RenderBox? child = lastChild;
while (child != null) {
// The x, y parameters have the top left of the node's box as the origin.
final StackParentData childParentData = child.parentData! as StackParentData;
final bool isHit = result.addWithPaintOffset(
offset: childParentData.offset,
position: position,
hitTest: (BoxHitTestResult result, Offset transformed) {
assert(transformed == position - childParentData.offset);
return child!.hitTest(result, position: transformed);
},
);
// NOTE MODIFIED
// if (isHit) return true;
childHit |= isHit;
child = childParentData.previousSibling;
}
// NOTE MODIFIED
return childHit;
// return false;
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5229 次 |
| 最近记录: |