如何使GestureDetector捕获堆栈中的水龙头?

时间:2019-08-12 18:56:48

标签: flutter

我正在尝试使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),
          ],
        ),
      ),
    );
  }

我知道我想在另一个小部件下面捕获轻敲事件可能很奇怪,但在我的实际情况下,顶部的小部件是透明的,有时会有渐变。

3 个答案:

答案 0 :(得分:1)

此解决方案非常简单,不使用任何技巧或技巧!只需使用flutter小部件:

您可以用Container包裹顶部小部件(在这种情况下为白色IgnorePointer),并将ignoring属性设置为true

Stack(
  children:[
    (...your down widget which should handle the tap...)

    IgnorePointer(
      ignoring:true,
      child: (... your top widget which must be transparent to any tap ...)
    )
  ]
)

然后,您的顶部小部件对任何水龙头都变得透明,并且水龙头将被顶部小部件下方的最顶部小部件捕获,而不被IgnorePointerignoring:true包裹。

例如,您可能对代码进行很少的更改即可达到所需的结果,例如:

@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)),
          ],
        ),
      ),
    );
  }

有关更多信息,请访问the official help page on flutter.dev

答案 1 :(得分:0)

您用一个完整的蓝色容器制作了一个容器(白色),因此,触摸它时,如果要管理它的触摸(白色容器),就放弃它(白色容器)还要在上面放置一个手势检测器。

一种简单的方法来测试将白色容器与蓝色容器反转的问题,并且会看到“轻击”的发生

这很好用:

Scaffold(
  body: Container(
    child: Stack(
      children: <Widget>[
         GestureDetector(
          behavior: HitTestBehavior.translucent,
          onTap: () {
            print('tap on white ');
          },
          child:
        Container(color: Colors.white)),

        GestureDetector(
          behavior: HitTestBehavior.translucent,
          onTap: () {
            print('tap on blue');
          },
          child: 
          SizedBox(
            height: 500,
            child: Container(color: Colors.blue),
          )
        ),
      ],
    ),
  ),
);

答案 2 :(得分:0)

好的,我想我自己找到了解决方案。我希望有一个更简单的解决方案,但对我有用。我遇到的问题是,堆栈小部件不会通过命中测试给所有孩子,而只能通过第一个被命中的孩子。我所做的是重新编写了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;
  }
}