使用 GestureDetector 捕捉 MaterialButton 子节点的手势

Mat*_*ino 5 gesturedetector flutter

我想要一个 MaterialButton 来检测 onTapDown、onTapUp 和 onTapCancel。

不幸的是,MaterialButtons 只检测 onPressed。所以我用 GestureDetector 包裹它,但对于 MaterialButtons,onPressed 是 @required 所以我将它设置为 () {}。问题是,即使我将 GestureDetector 行为设置为半透明,如果我点击按钮,只会触发 Button 的 onPressed 回调,并且我会丢失 GestureDetector 的 onTapDown 和 onTapUp 回调。如果我长按按钮,我只会触发 onTapDown,当我释放它时,会触发 onTapCancel。我永远无法以这种方式触发 onTapUp。

我仍然希望 MaterialButton 具有触觉/声音/视觉反馈功能。

我试图根本不设置 MaterialButton 上的 onPressed,并且(奇怪的是)它仍然有效,但该按钮被禁用并且根本没有提供任何反馈。

GestureDetector(
          behavior: HitTestBehavior.translucent,
          onTapDown: (_) {
            th.handleTap(i, 0);
          },
          onTapUp: (_) {
            th.handleTap(i, 1);
          },
          onTapCancel: () {
            th.handleTap(i, 2);
          },
          child: MaterialButton(
            onPressed: () {},
            child: Container(
              margin: EdgeInsets.all(5),
              child: Icon(icon),
            ),
          )
        )
Run Code Online (Sandbox Code Playgroud)

编辑:谢谢 Hugo Passos,出于某种原因,我认为 MaterialButtons 永远不会向他们的孩子传递手势。我越来越近了,但我仍然不在那里:我发现匹配 Gesture 大小的唯一方法是将它“夹在”两个容器之间,这对我来说似乎不是一个非常优雅的解决方案。顺便说一句,即使在这种情况下,我也遇到了两个问题:

1:如果我(很容易)点击按钮的边框,我仍然会触发 MaterialButton 的 onPressed 而不是 GestureDetector 的回调。我认为它的尺寸为零,所以它不可能永远不会被敲击。如果我将 GestureDetector 行为设置为不透明(对我来说仍然很奇怪),则不会显示此问题。

2:最重要的是:除非我不小心触发了它的 onPressed,否则我仍然无法获得原生的 MaterialButton 反馈功能。

Container(
margin: EdgeInsets.all(2),
        width: buttonSize,
        height: buttonSize,
        child: RaisedButton(
          padding: EdgeInsets.zero,
          onPressed: () {print("onTap");},
          child: Container(
            margin: EdgeInsets.zero,
            width: buttonSize,
            height: buttonSize,
            child: GestureDetector(
              onTapDown: (_) {
                th.handleTap(i, 0);
              },
              onTapUp: (_) {
                th.handleTap(i, 1);
              },
              onTapCancel: () {
                th.handleTap(i, 2);
              },
              child: Icon(icon)
            ),
          ),
        ),
      );
Run Code Online (Sandbox Code Playgroud)

Hug*_*sos 7

你必须做相反的事情。不要将RaisedButtona 包裹起来GestureDetector,而是将 a 包裹GestureDetector在 a 中RaisedButton。您还必须移除RaisedButton填充物,以便扩大GestureDetector作用区域。

RaisedButton(
  padding: EdgeInsets.zero,
  onPressed: () {},
  child: Container(
    height: 40,
    width: 80,
    child: GestureDetector(
      onTapDown: (_) => print('onTapDown'),
      onTapUp: (_) => print('onTapUp'),
      onTapCancel: () => print('onTapCancel'),
      child: Icon(icon),
    ),
  ),
),
Run Code Online (Sandbox Code Playgroud)

编辑

Center(
  child: RaisedButton(
    padding: EdgeInsets.zero,
    onPressed: () => print('onPressed'),
    child: GestureDetector(
      onTapDown: (_) => print('onTapDown'),
      onTapUp: (_) => print('onTapUp'),
      onTapCancel: () => print('onTapCancel'),
      child: Container(
        color: Colors.blue,
        height: 40,
        width: 80,
        child: Icon(icon),
      ),
    ),
  ),
);
Run Code Online (Sandbox Code Playgroud)

不过,你会得到一个调用 的小边框onPressed。如果这让您感到困扰,请将此代码包装在另一个 中Container,就像您在代码中所做的那样。

您可以通过调用处的方法轻松获得本机RaisedButton反馈功能。它会有相同的行为。onPressButtononTapUp

RaisedButton(
  ...
  onPressed: onPressButton,
  child: GestureDetector(
    ...
    onTapUp: (_) {
      onPressButton();
      print('onTapUp')
    },
    ...
  ),
),
Run Code Online (Sandbox Code Playgroud)